Skip to content

Commit 2f42e2e

Browse files
authored
Reduce small memory allocations when loading ply files (#147)
* Replace for-of loops to reduce memory allocations in hot-path for ply loading * Use temporary THREE.Quaternion and THREE.Vector instances to avoid allocations
1 parent 3f1d024 commit 2f42e2e

2 files changed

Lines changed: 22 additions & 13 deletions

File tree

src/ply.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,8 @@ export class PlyReader {
239239
// Parse all the items in the element
240240
const callback = elementCallback(element) ?? (() => {});
241241
for (let index = 0; index < count; index++) {
242-
for (const parser of parsers) {
243-
parser();
242+
for (let parserIndex = 0; parserIndex < parsers.length; parserIndex++) {
243+
parsers[parserIndex]();
244244
}
245245
callback(index, item);
246246
}
@@ -296,17 +296,17 @@ export class PlyReader {
296296
if (!sh1) {
297297
throw new Error("Missing sh1");
298298
}
299-
for (const [i, key] of sh1Props.entries()) {
300-
sh1[i] = ((item[key] as number) * 8) / 255 - 4;
299+
for (let i = 0; i < sh1Props.length; i++) {
300+
sh1[i] = ((item[sh1Props[i]] as number) * 8) / 255 - 4;
301301
}
302302
if (sh2) {
303-
for (const [i, key] of sh2Props.entries()) {
304-
sh2[i] = ((item[key] as number) * 8) / 255 - 4;
303+
for (let i = 0; i < sh2Props.length; i++) {
304+
sh2[i] = ((item[sh2Props[i]] as number) * 8) / 255 - 4;
305305
}
306306
}
307307
if (sh3) {
308-
for (const [i, key] of sh3Props.entries()) {
309-
sh3[i] = ((item[key] as number) * 8) / 255 - 4;
308+
for (let i = 0; i < sh3Props.length; i++) {
309+
sh3[i] = ((item[sh3Props[i]] as number) * 8) / 255 - 4;
310310
}
311311
}
312312
shCallback?.(index, sh1, sh2, sh3);

src/utils.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,10 @@ export function setPackedSplatScales(
499499
(packedSplats[i4 + 3] & 0xff000000);
500500
}
501501

502+
// Temporary storage used in `encodeQuatOCtXy88R8` and `decodeQuatOctXy88R8` to
503+
// avoid allocation new Quaternions and Vector3 instances.
504+
const tempQuaternion = new THREE.Quaternion();
505+
502506
// Encode the rotation quatX, quatY, quatZ, quatW in the packedSplats Uint32Array,
503507
// leaving all other fields as is.
504508
export function setPackedSplatQuat(
@@ -510,7 +514,7 @@ export function setPackedSplatQuat(
510514
quatW: number,
511515
) {
512516
const uQuat = encodeQuatOctXy88R8(
513-
new THREE.Quaternion(quatX, quatY, quatZ, quatW),
517+
tempQuaternion.set(quatX, quatY, quatZ, quatW),
514518
);
515519
// const uQuat = encodeQuatXyz888(new THREE.Quaternion(quatX, quatY, quatZ, quatW));
516520
// const uQuat = encodeQuatEulerXyz888(new THREE.Quaternion(quatX, quatY, quatZ, quatW));
@@ -960,6 +964,11 @@ export function decodeQuatXyz888(
960964
return out;
961965
}
962966

967+
// Temporary storage used in `encodeQuatOCtXy88R8` and `decodeQuatOctXy88R8` to
968+
// avoid allocation new Quaternions and Vector3 instances.
969+
const tempNormalizedQuaternion = new THREE.Quaternion();
970+
const tempAxis = new THREE.Vector3();
971+
963972
/**
964973
* Encodes a THREE.Quaternion into a 24‐bit integer.
965974
*
@@ -972,7 +981,7 @@ export function decodeQuatXyz888(
972981
*/
973982
export function encodeQuatOctXy88R8(q: THREE.Quaternion): number {
974983
// Force the minimal representation (q.w >= 0)
975-
const qnorm = q.clone().normalize();
984+
const qnorm = tempNormalizedQuaternion.copy(q).normalize();
976985
if (qnorm.w < 0) {
977986
qnorm.set(-qnorm.x, -qnorm.y, -qnorm.z, -qnorm.w);
978987
}
@@ -984,8 +993,8 @@ export function encodeQuatOctXy88R8(q: THREE.Quaternion): number {
984993
);
985994
const axis =
986995
xyz_norm < 1e-6
987-
? new THREE.Vector3(1, 0, 0)
988-
: new THREE.Vector3(qnorm.x, qnorm.y, qnorm.z).divideScalar(xyz_norm);
996+
? tempAxis.set(1, 0, 0)
997+
: tempAxis.set(qnorm.x, qnorm.y, qnorm.z).divideScalar(xyz_norm);
989998
// const foldAxis = (axis.z < 0);
990999

9911000
// --- Folded Octahedral Mapping (inline) ---
@@ -1036,7 +1045,7 @@ export function decodeQuatOctXy88R8(
10361045
const t = Math.max(-f_z, 0);
10371046
f_x += f_x >= 0 ? -t : t;
10381047
f_y += f_y >= 0 ? -t : t;
1039-
const axis = new THREE.Vector3(f_x, f_y, f_z).normalize();
1048+
const axis = tempAxis.set(f_x, f_y, f_z).normalize();
10401049

10411050
// Decode the angle: θ ∈ [0,π]
10421051
const theta = (angleInt / 255) * Math.PI;

0 commit comments

Comments
 (0)