Cedric
August 4, 2025, 8:48am
3
Y flip needs to happen because of the first .PLY format that was not in Babylon space coordinate system. I chose to transform individual vertices instead of having non uniform scaling in GS transform.
There are 2 operations that transform the scaling value into actual geometry scaling:
A scaling matrix here with *2 the value
maximum.maximizeInPlaceFromFloats(x, y, z);
quaternion.set(
(uBuffer[32 * index + 28 + 1] - 127.5) / 127.5,
(uBuffer[32 * index + 28 + 2] - 127.5) / 127.5,
(uBuffer[32 * index + 28 + 3] - 127.5) / 127.5,
-(uBuffer[32 * index + 28 + 0] - 127.5) / 127.5
);
quaternion.toRotationMatrix(matrixRotation);
Matrix.ScalingToRef(fBuffer[8 * index + 3 + 0] * 2, fBuffer[8 * index + 3 + 1] * 2, fBuffer[8 * index + 3 + 2] * 2, matrixScale);
const m = matrixRotation.multiplyToRef(matrixScale, TmpVectors.Matrix[0]).m;
const covariances = this._tmpCovariances;
covariances[0] = m[0] * m[0] + m[1] * m[1] + m[2] * m[2];
covariances[1] = m[0] * m[4] + m[1] * m[5] + m[2] * m[6];
covariances[2] = m[0] * m[8] + m[1] * m[9] + m[2] * m[10];
covariances[3] = m[4] * m[4] + m[5] * m[5] + m[6] * m[6];
covariances[4] = m[4] * m[8] + m[5] * m[9] + m[6] * m[10];
covariances[5] = m[8] * m[8] + m[9] * m[9] + m[10] * m[10];
and here for covariance:
(uBuffer[32 * index + 28 + 3] - 127.5) / 127.5,
-(uBuffer[32 * index + 28 + 0] - 127.5) / 127.5
);
quaternion.toRotationMatrix(matrixRotation);
Matrix.ScalingToRef(fBuffer[8 * index + 3 + 0] * 2, fBuffer[8 * index + 3 + 1] * 2, fBuffer[8 * index + 3 + 2] * 2, matrixScale);
const m = matrixRotation.multiplyToRef(matrixScale, TmpVectors.Matrix[0]).m;
const covariances = this._tmpCovariances;
covariances[0] = m[0] * m[0] + m[1] * m[1] + m[2] * m[2];
covariances[1] = m[0] * m[4] + m[1] * m[5] + m[2] * m[6];
covariances[2] = m[0] * m[8] + m[1] * m[9] + m[2] * m[10];
covariances[3] = m[4] * m[4] + m[5] * m[5] + m[6] * m[6];
covariances[4] = m[4] * m[8] + m[5] * m[9] + m[6] * m[10];
covariances[5] = m[8] * m[8] + m[9] * m[9] + m[10] * m[10];
// normalize covA, covB
let factor = -10000;
for (let covIndex = 0; covIndex < 6; covIndex++) {
factor = Math.max(factor, Math.abs(covariances[covIndex]));
So, basically, if you want a splat radius of 0.5, compute its square root (sqrt(0.5) = 0.70710678118) then divide by 2.
I changed the shader to have a saturation of alpha (0 or 1) to verify that and got:
// uniform scale
fBuffer[8 * ind + 3 + 0] = Math.sqrt(0.5) * 0.5;
fBuffer[8 * ind + 3 + 1] = 1;
fBuffer[8 * ind + 3 + 2] = Math.sqrt(0.5) * 0.5;
Beware with alpha computation, it will be difficult to have perfectly fitting splats. they will be appear smaller than the size you want.