gsplat_library / src /splats /SplatData.ts
bilca's picture
Upload 56 files
352fb85 verified
raw
history blame
7.7 kB
import { Vector3 } from "../math/Vector3";
import { Quaternion } from "../math/Quaternion";
import { Matrix3 } from "../math/Matrix3";
class SplatData {
static RowLength = 3 * 4 + 3 * 4 + 4 + 4;
public changed = false;
public detached = false;
private _vertexCount: number;
private _positions: Float32Array;
private _rotations: Float32Array;
private _scales: Float32Array;
private _colors: Uint8Array;
private _selection: Uint8Array;
translate: (translation: Vector3) => void;
rotate: (rotation: Quaternion) => void;
scale: (scale: Vector3) => void;
serialize: () => Uint8Array;
reattach: (
positions: ArrayBufferLike,
rotations: ArrayBufferLike,
scales: ArrayBufferLike,
colors: ArrayBufferLike,
selection: ArrayBufferLike,
) => void;
constructor(
vertexCount: number = 0,
positions: Float32Array | null = null,
rotations: Float32Array | null = null,
scales: Float32Array | null = null,
colors: Uint8Array | null = null,
) {
this._vertexCount = vertexCount;
this._positions = positions || new Float32Array(0);
this._rotations = rotations || new Float32Array(0);
this._scales = scales || new Float32Array(0);
this._colors = colors || new Uint8Array(0);
this._selection = new Uint8Array(this.vertexCount);
this.translate = (translation: Vector3) => {
for (let i = 0; i < this.vertexCount; i++) {
this.positions[3 * i + 0] += translation.x;
this.positions[3 * i + 1] += translation.y;
this.positions[3 * i + 2] += translation.z;
}
this.changed = true;
};
this.rotate = (rotation: Quaternion) => {
const R = Matrix3.RotationFromQuaternion(rotation).buffer;
for (let i = 0; i < this.vertexCount; i++) {
const x = this.positions[3 * i + 0];
const y = this.positions[3 * i + 1];
const z = this.positions[3 * i + 2];
this.positions[3 * i + 0] = R[0] * x + R[1] * y + R[2] * z;
this.positions[3 * i + 1] = R[3] * x + R[4] * y + R[5] * z;
this.positions[3 * i + 2] = R[6] * x + R[7] * y + R[8] * z;
const currentRotation = new Quaternion(
this.rotations[4 * i + 1],
this.rotations[4 * i + 2],
this.rotations[4 * i + 3],
this.rotations[4 * i + 0],
);
const newRot = rotation.multiply(currentRotation);
this.rotations[4 * i + 1] = newRot.x;
this.rotations[4 * i + 2] = newRot.y;
this.rotations[4 * i + 3] = newRot.z;
this.rotations[4 * i + 0] = newRot.w;
}
this.changed = true;
};
this.scale = (scale: Vector3) => {
for (let i = 0; i < this.vertexCount; i++) {
this.positions[3 * i + 0] *= scale.x;
this.positions[3 * i + 1] *= scale.y;
this.positions[3 * i + 2] *= scale.z;
this.scales[3 * i + 0] *= scale.x;
this.scales[3 * i + 1] *= scale.y;
this.scales[3 * i + 2] *= scale.z;
}
this.changed = true;
};
this.serialize = () => {
const data = new Uint8Array(this.vertexCount * SplatData.RowLength);
const f_buffer = new Float32Array(data.buffer);
const u_buffer = new Uint8Array(data.buffer);
for (let i = 0; i < this.vertexCount; i++) {
f_buffer[8 * i + 0] = this.positions[3 * i + 0];
f_buffer[8 * i + 1] = this.positions[3 * i + 1];
f_buffer[8 * i + 2] = this.positions[3 * i + 2];
u_buffer[32 * i + 24 + 0] = this.colors[4 * i + 0];
u_buffer[32 * i + 24 + 1] = this.colors[4 * i + 1];
u_buffer[32 * i + 24 + 2] = this.colors[4 * i + 2];
u_buffer[32 * i + 24 + 3] = this.colors[4 * i + 3];
f_buffer[8 * i + 3 + 0] = this.scales[3 * i + 0];
f_buffer[8 * i + 3 + 1] = this.scales[3 * i + 1];
f_buffer[8 * i + 3 + 2] = this.scales[3 * i + 2];
u_buffer[32 * i + 28 + 0] = (this.rotations[4 * i + 0] * 128 + 128) & 0xff;
u_buffer[32 * i + 28 + 1] = (this.rotations[4 * i + 1] * 128 + 128) & 0xff;
u_buffer[32 * i + 28 + 2] = (this.rotations[4 * i + 2] * 128 + 128) & 0xff;
u_buffer[32 * i + 28 + 3] = (this.rotations[4 * i + 3] * 128 + 128) & 0xff;
}
return data;
};
this.reattach = (
positions: ArrayBufferLike,
rotations: ArrayBufferLike,
scales: ArrayBufferLike,
colors: ArrayBufferLike,
selection: ArrayBufferLike,
) => {
console.assert(
positions.byteLength === this.vertexCount * 3 * 4,
`Expected ${this.vertexCount * 3 * 4} bytes, got ${positions.byteLength} bytes`,
);
this._positions = new Float32Array(positions);
this._rotations = new Float32Array(rotations);
this._scales = new Float32Array(scales);
this._colors = new Uint8Array(colors);
this._selection = new Uint8Array(selection);
this.detached = false;
};
}
static Deserialize(data: Uint8Array): SplatData {
const vertexCount = data.length / SplatData.RowLength;
const positions = new Float32Array(3 * vertexCount);
const rotations = new Float32Array(4 * vertexCount);
const scales = new Float32Array(3 * vertexCount);
const colors = new Uint8Array(4 * vertexCount);
const f_buffer = new Float32Array(data.buffer);
const u_buffer = new Uint8Array(data.buffer);
for (let i = 0; i < vertexCount; i++) {
positions[3 * i + 0] = f_buffer[8 * i + 0];
positions[3 * i + 1] = f_buffer[8 * i + 1];
positions[3 * i + 2] = f_buffer[8 * i + 2];
rotations[4 * i + 0] = (u_buffer[32 * i + 28 + 0] - 128) / 128;
rotations[4 * i + 1] = (u_buffer[32 * i + 28 + 1] - 128) / 128;
rotations[4 * i + 2] = (u_buffer[32 * i + 28 + 2] - 128) / 128;
rotations[4 * i + 3] = (u_buffer[32 * i + 28 + 3] - 128) / 128;
scales[3 * i + 0] = f_buffer[8 * i + 3 + 0];
scales[3 * i + 1] = f_buffer[8 * i + 3 + 1];
scales[3 * i + 2] = f_buffer[8 * i + 3 + 2];
colors[4 * i + 0] = u_buffer[32 * i + 24 + 0];
colors[4 * i + 1] = u_buffer[32 * i + 24 + 1];
colors[4 * i + 2] = u_buffer[32 * i + 24 + 2];
colors[4 * i + 3] = u_buffer[32 * i + 24 + 3];
}
return new SplatData(vertexCount, positions, rotations, scales, colors);
}
get vertexCount() {
return this._vertexCount;
}
get positions() {
return this._positions;
}
get rotations() {
return this._rotations;
}
get scales() {
return this._scales;
}
get colors() {
return this._colors;
}
get selection() {
return this._selection;
}
clone() {
return new SplatData(
this.vertexCount,
new Float32Array(this.positions),
new Float32Array(this.rotations),
new Float32Array(this.scales),
new Uint8Array(this.colors),
);
}
}
export { SplatData };