Background
When using potree(potree-core) to load a large point cloud dataset, it involves the scenario of obtaining all point cloud data for processing, so this method is in place.
Core Code
function getPoints() {
const position = new Float32Array(MAX_POINTS * 3);
const intensity = new Float32Array(MAX_POINTS);
const matrixCache = new Map<PointCloudOctree, THREE.Matrix4>();
this.pointClouds.forEach((pointCloud) => {
matrixCache.set(pointCloud, pointCloud.matrixWorld.clone());
});
let offset = 0;
this.pointClouds.forEach((pointCloud: PointCloudOctree) => {
const pcMatrix = matrixCache.get(pointCloud);
if (!pcMatrix) return;
pointCloud.visibleGeometry.forEach((node) => {
const geometry = node.geometry;
if (!geometry?.attributes.position) return;
const nodeMatrix = new THREE.Matrix4().makeTranslation(
...node.boundingBox.min.toArray(),
);
const finalMatrix = new THREE.Matrix4().multiplyMatrices(pcMatrix, nodeMatrix);
// Batch Matrix Transformation
const positionArray = geometry.attributes.position.array;
const positionCount = positionArray.length;
const elements = finalMatrix.elements;
const transformed = new Float32Array(positionCount);
// SIMD
for (let i = 0; i < positionCount; i += 3) {
const x = positionArray[i];
const y = positionArray[i + 1];
const z = positionArray[i + 2];
transformed[i] = elements[0] * x + elements[4] * y + elements[8] * z + elements[12];
transformed[i + 1] = elements[1] * x + elements[5] * y + elements[9] * z + elements[13];
transformed[i + 2] = elements[2] * x + elements[6] * y + elements[10] * z + elements[14];
}
position.set(transformed, offset * 3);
const intensityArray = geometry.attributes.intensity.array || new Float32Array(positionCount / 3).fill(1);
intensity.set(intensityArray, offset);
offset += positionCount / 3;
});
});
}