UNPKG

potree

Version:

WebGL point cloud viewer - WORK IN PROGRESS

281 lines (219 loc) 8.4 kB
/* global onmessage:true postMessage:false Module */ /* exported onmessage */ // http://jsperf.com/uint8array-vs-dataview3/3 function CustomView (buffer) { this.buffer = buffer; this.u8 = new Uint8Array(buffer); var tmp = new ArrayBuffer(4); var tmpf = new Float32Array(tmp); var tmpu8 = new Uint8Array(tmp); this.getUint32 = function (i) { return (this.u8[i + 3] << 24) | (this.u8[i + 2] << 16) | (this.u8[i + 1] << 8) | this.u8[i]; }; this.getUint16 = function (i) { return (this.u8[i + 1] << 8) | this.u8[i]; }; this.getFloat = function (i) { tmpu8[0] = this.u8[i + 0]; tmpu8[1] = this.u8[i + 1]; tmpu8[2] = this.u8[i + 2]; tmpu8[3] = this.u8[i + 3]; return tmpf[0]; }; this.getUint8 = function (i) { return this.u8[i]; }; } function networkToNative (val) { return ((val & 0x00FF) << 24) | ((val & 0xFF00) << 8) | ((val >> 8) & 0xFF00) | ((val >> 24) & 0x00FF); } var decompress = function (schema, input, numPoints) { var x = new Module.DynamicLASZip(); var abInt = new Uint8Array(input); var buf = Module._malloc(input.byteLength); Module.HEAPU8.set(abInt, buf); x.open(buf, input.byteLength); var pointSize = 0; schema.forEach(function (f) { pointSize += f.size; if (f.type === 'floating') x.addFieldFloating(f.size); else if (f.type === 'unsigned') x.addFieldUnsigned(f.size); else if (f.type === 'signed') x.addFieldSigned(f.size); else throw new Error('Unrecognized field desc:', f); }); var out = Module._malloc(numPoints * pointSize); for (var i = 0; i < numPoints; i++) { x.getPoint(out + i * pointSize); } var ret = new Uint8Array(numPoints * pointSize); ret.set(Module.HEAPU8.subarray(out, out + numPoints * pointSize)); Module._free(out); Module._free(buf); return ret.buffer; }; Potree = {}; onmessage = function (event) { var NUM_POINTS_BYTES = 4; var buffer = event.data.buffer; var pointAttributes = event.data.pointAttributes; var view = new DataView( buffer, buffer.byteLength - NUM_POINTS_BYTES, NUM_POINTS_BYTES); var numPoints = networkToNative(view.getUint32(0)); buffer = buffer.slice(0, buffer.byteLength - NUM_POINTS_BYTES); buffer = decompress(event.data.schema, buffer, numPoints); var cv = new CustomView(buffer); // event.data.version // event.data.min // event.data.max var nodeOffset = event.data.offset; var scale = event.data.scale; var tightBoxMin = [ Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY ]; var tightBoxMax = [ Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY ]; var attributeBuffers = {}; var offset = 0; var pointSize = pointAttributes.byteSize; let mean = [0, 0, 0]; for (let i = 0; i < pointAttributes.attributes.length; i++) { var pointAttribute = pointAttributes.attributes[i]; if (pointAttribute.name === Potree.PointAttribute.POSITION_CARTESIAN.name) { let buff = new ArrayBuffer(numPoints * 4 * 3); let positions = new Float32Array(buff); for (let j = 0; j < numPoints; ++j) { let ux = cv.getUint32(offset + j * pointSize + 0); let uy = cv.getUint32(offset + j * pointSize + 4); let uz = cv.getUint32(offset + j * pointSize + 8); let x = (scale * ux) + nodeOffset[0]; let y = (scale * uy) + nodeOffset[1]; let z = (scale * uz) + nodeOffset[2]; positions[3 * j + 0] = x; positions[3 * j + 1] = y; positions[3 * j + 2] = z; mean[0] += x / numPoints; mean[1] += y / numPoints; mean[2] += z / numPoints; tightBoxMin[0] = Math.min(tightBoxMin[0], positions[3 * j + 0]); tightBoxMin[1] = Math.min(tightBoxMin[1], positions[3 * j + 1]); tightBoxMin[2] = Math.min(tightBoxMin[2], positions[3 * j + 2]); tightBoxMax[0] = Math.max(tightBoxMax[0], positions[3 * j + 0]); tightBoxMax[1] = Math.max(tightBoxMax[1], positions[3 * j + 1]); tightBoxMax[2] = Math.max(tightBoxMax[2], positions[3 * j + 2]); } attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute }; } else if (pointAttribute.name === Potree.PointAttribute.COLOR_PACKED.name) { let buff = new ArrayBuffer(numPoints * 3); let colors = new Uint8Array(buff); let div = event.data.normalize.color ? 256 : 1; for (let j = 0; j < numPoints; ++j) { colors[3 * j + 0] = cv.getUint16(offset + j * pointSize + 0) / div; colors[3 * j + 1] = cv.getUint16(offset + j * pointSize + 2) / div; colors[3 * j + 2] = cv.getUint16(offset + j * pointSize + 4) / div; } attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute }; } else if (pointAttribute.name === Potree.PointAttribute.INTENSITY.name) { let buff = new ArrayBuffer(numPoints * 4); let intensities = new Float32Array(buff); for (let j = 0; j < numPoints; ++j) { var intensity = cv.getUint16(offset + j * pointSize); // if (event.data.normalize.intensity) { // intensity = Math.floor(intensity / 256); // } intensities[j] = intensity; } attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute }; } else if (pointAttribute.name === Potree.PointAttribute.CLASSIFICATION.name) { let buff = new ArrayBuffer(numPoints * 4); let classifications = new Float32Array(buff); for (let j = 0; j < numPoints; ++j) { var classification = cv.getUint8(offset + j * pointSize); classifications[j] = classification; } attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute }; } else if (pointAttribute.name === Potree.PointAttribute.NORMAL_SPHEREMAPPED.name) { let buff = new ArrayBuffer(numPoints * 4 * 3); let normals = new Float32Array(buff); for (let j = 0; j < numPoints; ++j) { let bx = cv.getUint8(offset + j * pointSize + 0); let by = cv.getUint8(offset + j * pointSize + 1); let ex = bx / 255; let ey = by / 255; let nx = ex * 2 - 1; let ny = ey * 2 - 1; let nz = 1; let nw = -1; let l = (nx * (-nx)) + (ny * (-ny)) + (nz * (-nw)); nz = l; nx = nx * Math.sqrt(l); ny = ny * Math.sqrt(l); nx = nx * 2; ny = ny * 2; nz = nz * 2 - 1; normals[3 * j + 0] = nx; normals[3 * j + 1] = ny; normals[3 * j + 2] = nz; } attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute }; } else if (pointAttribute.name === Potree.PointAttribute.NORMAL_OCT16.name) { let buff = new ArrayBuffer(numPoints * 4 * 3); let normals = new Float32Array(buff); for (let j = 0; j < numPoints; ++j) { let bx = cv.getUint8(offset + j * pointSize + 0); let by = cv.getUint8(offset + j * pointSize + 1); let u = (bx / 255) * 2 - 1; let v = (by / 255) * 2 - 1; let z = 1 - Math.abs(u) - Math.abs(v); let x = 0; let y = 0; if (z >= 0) { x = u; y = v; } else { x = -(v / Math.sign(v) - 1) / Math.sign(u); y = -(u / Math.sign(u) - 1) / Math.sign(v); } var length = Math.sqrt(x * x + y * y + z * z); x = x / length; y = y / length; z = z / length; normals[3 * j + 0] = x; normals[3 * j + 1] = y; normals[3 * j + 2] = z; } attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute }; } else if (pointAttribute.name === Potree.PointAttribute.NORMAL.name) { let buff = new ArrayBuffer(numPoints * 4 * 3); let normals = new Float32Array(buff); for (var j = 0; j < numPoints; ++j) { let x = cv.getFloat(offset + j * pointSize + 0); let y = cv.getFloat(offset + j * pointSize + 4); let z = cv.getFloat(offset + j * pointSize + 8); normals[3 * j + 0] = x; normals[3 * j + 1] = y; normals[3 * j + 2] = z; } attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute }; } offset += pointAttribute.byteSize; } var indices = new ArrayBuffer(numPoints * 4); var iIndices = new Uint32Array(indices); for (let i = 0; i < numPoints; i++) { iIndices[i] = i; } var message = { mean: mean, attributeBuffers: attributeBuffers, tightBoundingBox: { min: tightBoxMin, max: tightBoxMax }, indices: indices }; var transferables = []; for (var property in message.attributeBuffers) { if (message.attributeBuffers.hasOwnProperty(property)) { transferables.push(message.attributeBuffers[property].buffer); } } transferables.push(message.indices); postMessage(message, transferables); };