OctreeLoader.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. import * as THREE from "../../../../libs/three.js/build/three.module.js";
  2. import {PointAttribute, PointAttributes, PointAttributeTypes} from "../../../loader/PointAttributes.js";
  3. import {OctreeGeometry, OctreeGeometryNode} from "./OctreeGeometry.js";
  4. // let loadedNodes = new Set();
  5. export class NodeLoader{
  6. constructor(url){
  7. this.url = url;
  8. }
  9. async load(node){
  10. if(node.loaded || node.loading){
  11. return;
  12. }
  13. node.loading = true;
  14. Potree.numNodesLoading++;
  15. // console.log(node.name, node.numPoints);
  16. // if(loadedNodes.has(node.name)){
  17. // // debugger;
  18. // }
  19. // loadedNodes.add(node.name);
  20. try{
  21. if(node.nodeType === 2){
  22. await this.loadHierarchy(node);
  23. }
  24. let {byteOffset, byteSize} = node;
  25. let urlOctree = `${this.url}/../octree.bin`;
  26. let first = byteOffset;
  27. let last = byteOffset + byteSize - 1n; //1n这种写法部分浏览器不支持
  28. let buffer;
  29. if(byteSize === 0n){
  30. buffer = new ArrayBuffer(0);
  31. console.warn(`loaded node with 0 bytes: ${node.name}`);
  32. }else{
  33. let response = await fetch(urlOctree, {
  34. headers: {
  35. 'content-type': 'multipart/byteranges',
  36. 'Range': `bytes=${first}-${last}`,
  37. },
  38. });
  39. buffer = await response.arrayBuffer();
  40. }
  41. let workerPath;
  42. if(this.metadata.encoding === "BROTLI"){
  43. workerPath = Potree.scriptPath + '/workers/2.0/DecoderWorker_brotli.js';
  44. }else{
  45. workerPath = Potree.scriptPath + '/workers/2.0/DecoderWorker.js';
  46. }
  47. let worker = Potree.workerPool.getWorker(workerPath);
  48. worker.onmessage = function (e) {
  49. let data = e.data;
  50. let buffers = data.attributeBuffers;
  51. Potree.workerPool.returnWorker(workerPath, worker);
  52. let geometry = new THREE.BufferGeometry();
  53. for(let property in buffers){
  54. let buffer = buffers[property].buffer;
  55. if(property === "position"){
  56. geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(buffer), 3));
  57. }else if(property === "rgba"){
  58. geometry.setAttribute('rgba', new THREE.BufferAttribute(new Uint8Array(buffer), 4, true));
  59. }else if(property === "NORMAL"){
  60. //geometry.setAttribute('rgba', new THREE.BufferAttribute(new Uint8Array(buffer), 4, true));
  61. geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(buffer), 3));
  62. }else if (property === "INDICES") {
  63. let bufferAttribute = new THREE.BufferAttribute(new Uint8Array(buffer), 4);
  64. bufferAttribute.normalized = true;
  65. geometry.setAttribute('indices', bufferAttribute);
  66. }else{
  67. const bufferAttribute = new THREE.BufferAttribute(new Float32Array(buffer), 1);
  68. let batchAttribute = buffers[property].attribute;
  69. bufferAttribute.potree = {
  70. offset: buffers[property].offset,
  71. scale: buffers[property].scale,
  72. preciseBuffer: buffers[property].preciseBuffer,
  73. range: batchAttribute.range,
  74. };
  75. geometry.setAttribute(property, bufferAttribute);
  76. }
  77. }
  78. // indices ??
  79. node.density = data.density;
  80. node.geometry = geometry;
  81. node.loaded = true;
  82. node.loading = false;
  83. Potree.numNodesLoading--;
  84. };
  85. let pointAttributes = node.octreeGeometry.pointAttributes;
  86. let scale = node.octreeGeometry.scale;
  87. let box = node.boundingBox;
  88. let min = node.octreeGeometry.offset.clone().add(box.min);
  89. let size = box.max.clone().sub(box.min);
  90. let max = min.clone().add(size);
  91. let numPoints = node.numPoints;
  92. let offset = node.octreeGeometry.loader.offset;
  93. let message = {
  94. name: node.name,
  95. buffer: buffer,
  96. pointAttributes: pointAttributes,
  97. scale: scale,
  98. min: min,
  99. max: max,
  100. size: size,
  101. offset: offset,
  102. numPoints: numPoints
  103. };
  104. worker.postMessage(message, [message.buffer]);
  105. }catch(e){
  106. node.loaded = false;
  107. node.loading = false;
  108. Potree.numNodesLoading--;
  109. console.log(`failed to load ${node.name}`);
  110. console.log(e);
  111. console.log(`trying again!`);
  112. }
  113. }
  114. parseHierarchy(node, buffer){
  115. let view = new DataView(buffer);
  116. let tStart = performance.now();
  117. let bytesPerNode = 22;
  118. let numNodes = buffer.byteLength / bytesPerNode;
  119. let octree = node.octreeGeometry;
  120. // let nodes = [node];
  121. let nodes = new Array(numNodes);
  122. nodes[0] = node;
  123. let nodePos = 1;
  124. for(let i = 0; i < numNodes; i++){
  125. let current = nodes[i];
  126. let type = view.getUint8(i * bytesPerNode + 0);
  127. let childMask = view.getUint8(i * bytesPerNode + 1);
  128. let numPoints = view.getUint32(i * bytesPerNode + 2, true);
  129. let byteOffset = view.getBigInt64(i * bytesPerNode + 6, true);
  130. let byteSize = view.getBigInt64(i * bytesPerNode + 14, true);
  131. // if(byteSize === 0n){
  132. // // debugger;
  133. // }
  134. if(current.nodeType === 2){
  135. // replace proxy with real node
  136. current.byteOffset = byteOffset;
  137. current.byteSize = byteSize;
  138. current.numPoints = numPoints;
  139. }else if(type === 2){
  140. // load proxy
  141. current.hierarchyByteOffset = byteOffset;
  142. current.hierarchyByteSize = byteSize;
  143. current.numPoints = numPoints;
  144. }else{
  145. // load real node
  146. current.byteOffset = byteOffset;
  147. current.byteSize = byteSize;
  148. current.numPoints = numPoints;
  149. }
  150. current.nodeType = type;
  151. if(current.nodeType === 2){
  152. continue;
  153. }
  154. for(let childIndex = 0; childIndex < 8; childIndex++){
  155. let childExists = ((1 << childIndex) & childMask) !== 0;
  156. if(!childExists){
  157. continue;
  158. }
  159. let childName = current.name + childIndex;
  160. let childAABB = createChildAABB(current.boundingBox, childIndex);
  161. let child = new OctreeGeometryNode(childName, octree, childAABB);
  162. child.name = childName;
  163. child.spacing = current.spacing / 2;
  164. child.level = current.level + 1;
  165. current.children[childIndex] = child;
  166. child.parent = current;
  167. // nodes.push(child);
  168. nodes[nodePos] = child;
  169. nodePos++;
  170. }
  171. // if((i % 500) === 0){
  172. // yield;
  173. // }
  174. }
  175. let duration = (performance.now() - tStart);
  176. // if(duration > 20){
  177. // let msg = `duration: ${duration}ms, numNodes: ${numNodes}`;
  178. // console.log(msg);
  179. // }
  180. }
  181. async loadHierarchy(node){
  182. let {hierarchyByteOffset, hierarchyByteSize} = node;
  183. let hierarchyPath = `${this.url}/../hierarchy.bin`;
  184. let first = hierarchyByteOffset;
  185. let last = first + hierarchyByteSize - 1n;
  186. let response = await fetch(hierarchyPath, {
  187. headers: {
  188. 'content-type': 'multipart/byteranges',
  189. 'Range': `bytes=${first}-${last}`,
  190. },
  191. });
  192. let buffer = await response.arrayBuffer();
  193. this.parseHierarchy(node, buffer);
  194. // let promise = new Promise((resolve) => {
  195. // let generator = this.parseHierarchy(node, buffer);
  196. // let repeatUntilDone = () => {
  197. // let result = generator.next();
  198. // if(result.done){
  199. // resolve();
  200. // }else{
  201. // requestAnimationFrame(repeatUntilDone);
  202. // }
  203. // };
  204. // repeatUntilDone();
  205. // });
  206. // await promise;
  207. }
  208. }
  209. let tmpVec3 = new THREE.Vector3();
  210. function createChildAABB(aabb, index){
  211. let min = aabb.min.clone();
  212. let max = aabb.max.clone();
  213. let size = tmpVec3.subVectors(max, min);
  214. if ((index & 0b0001) > 0) {
  215. min.z += size.z / 2;
  216. } else {
  217. max.z -= size.z / 2;
  218. }
  219. if ((index & 0b0010) > 0) {
  220. min.y += size.y / 2;
  221. } else {
  222. max.y -= size.y / 2;
  223. }
  224. if ((index & 0b0100) > 0) {
  225. min.x += size.x / 2;
  226. } else {
  227. max.x -= size.x / 2;
  228. }
  229. return new THREE.Box3(min, max);
  230. }
  231. let typenameTypeattributeMap = {
  232. "double": PointAttributeTypes.DATA_TYPE_DOUBLE,
  233. "float": PointAttributeTypes.DATA_TYPE_FLOAT,
  234. "int8": PointAttributeTypes.DATA_TYPE_INT8,
  235. "uint8": PointAttributeTypes.DATA_TYPE_UINT8,
  236. "int16": PointAttributeTypes.DATA_TYPE_INT16,
  237. "uint16": PointAttributeTypes.DATA_TYPE_UINT16,
  238. "int32": PointAttributeTypes.DATA_TYPE_INT32,
  239. "uint32": PointAttributeTypes.DATA_TYPE_UINT32,
  240. "int64": PointAttributeTypes.DATA_TYPE_INT64,
  241. "uint64": PointAttributeTypes.DATA_TYPE_UINT64,
  242. }
  243. export class OctreeLoader{
  244. static parseAttributes(jsonAttributes){
  245. let attributes = new PointAttributes();
  246. let replacements = {
  247. "rgb": "rgba",
  248. };
  249. for (const jsonAttribute of jsonAttributes) {
  250. let {name, description, size, numElements, elementSize, min, max} = jsonAttribute;
  251. let type = typenameTypeattributeMap[jsonAttribute.type];
  252. let potreeAttributeName = replacements[name] ? replacements[name] : name;
  253. let attribute = new PointAttribute(potreeAttributeName, type, numElements);
  254. if(numElements === 1){
  255. attribute.range = [min[0], max[0]];
  256. }else{
  257. attribute.range = [min, max];
  258. }
  259. if (name === "gps-time") { // HACK: Guard against bad gpsTime range in metadata, see potree/potree#909
  260. if (attribute.range[0] === attribute.range[1]) {
  261. attribute.range[1] += 1;
  262. }
  263. }
  264. attribute.initialRange = attribute.range;
  265. attributes.add(attribute);
  266. }
  267. {
  268. // check if it has normals
  269. let hasNormals =
  270. attributes.attributes.find(a => a.name === "NormalX") !== undefined &&
  271. attributes.attributes.find(a => a.name === "NormalY") !== undefined &&
  272. attributes.attributes.find(a => a.name === "NormalZ") !== undefined;
  273. if(hasNormals){
  274. let vector = {
  275. name: "NORMAL",
  276. attributes: ["NormalX", "NormalY", "NormalZ"],
  277. };
  278. attributes.addVector(vector);
  279. }
  280. }
  281. return attributes;
  282. }
  283. static async load(url){
  284. let response = await fetch(url);
  285. let metadata = await response.json();
  286. let attributes = OctreeLoader.parseAttributes(metadata.attributes);
  287. let loader = new NodeLoader(url);
  288. loader.metadata = metadata;
  289. loader.attributes = attributes;
  290. loader.scale = metadata.scale;
  291. loader.offset = metadata.offset;
  292. let octree = new OctreeGeometry();
  293. octree.url = url;
  294. octree.spacing = metadata.spacing;
  295. octree.scale = metadata.scale;
  296. // let aPosition = metadata.attributes.find(a => a.name === "position");
  297. // octree
  298. let min = new THREE.Vector3(...metadata.boundingBox.min);
  299. let max = new THREE.Vector3(...metadata.boundingBox.max);
  300. let boundingBox = new THREE.Box3(min, max);
  301. let offset = min.clone();
  302. boundingBox.min.sub(offset);
  303. boundingBox.max.sub(offset);
  304. octree.projection = metadata.projection;
  305. octree.boundingBox = boundingBox;
  306. octree.tightBoundingBox = boundingBox.clone();
  307. octree.boundingSphere = boundingBox.getBoundingSphere(new THREE.Sphere());
  308. octree.tightBoundingSphere = boundingBox.getBoundingSphere(new THREE.Sphere());
  309. octree.offset = offset;
  310. octree.pointAttributes = OctreeLoader.parseAttributes(metadata.attributes);
  311. octree.loader = loader;
  312. let root = new OctreeGeometryNode("r", octree, boundingBox);
  313. root.level = 0;
  314. root.nodeType = 2;
  315. root.hierarchyByteOffset = 0n;
  316. root.hierarchyByteSize = BigInt(metadata.hierarchy.firstChunkSize);
  317. root.hasChildren = false;
  318. root.spacing = octree.spacing;
  319. root.byteOffset = 0;
  320. octree.root = root;
  321. loader.load(root);
  322. let result = {
  323. geometry: octree,
  324. };
  325. return result;
  326. }
  327. };