PAJAMA / LEARN
← Course overview

Ship and explain the renderer / 11 OF 12

A model file is a promise to the renderer

After this lessonTrace a trained number through a binary record, activation and shader field; distinguish export from a resumable checkpoint.

A PLY can load successfully and still render nonsense. The reader may understand the bytes while misunderstanding what the numbers mean.

Build the idea, one step at a time

Need a math refresher?

Open only the tool you need; return here to use it in the next step.

Exponentials & logarithms

STEP 1 / 5

Container is not semantics

PLY declares properties, types and element counts. It does not impose a universal Gaussian schema. A field called f_dc_0 might mean an SH DC coefficient in one exporter and direct red in another. Names alone are insufficient: record activations, color conventions, orientation, units and time normalization.

PUT NUMBERS IN

Select field 20 below. The stored β is ln(4) ≈ 1.386294 and base opacity is sigmoid(β) = 0.8. Select scale_0: stored ln(0.2) ≈ −1.609438 means world-space scale 0.2, not a negative width.

FORMULA → RUNNING CODE

Find the same operation in the code

These excerpts are read from the current repository when the site is built. Expand one to inspect it; the full snapshot opens in a separate tab.

scripts/train_toy_stg.pyL98–106

The exporter makes the raw-versus-activated distinction explicit.

    rows = np.zeros((len(teacher[0]),32), dtype="<f4")
    rows[:, :3] = fitted[0].detach().cpu().numpy()
    rows[:, 3] = 0.5
    rows[:, 4] = math.log(0.55)
    rows[:, 8:11] = fitted[1].detach().cpu().numpy()
    rows[:, 17:20] = fitted[2].sigmoid().detach().cpu().numpy()
    rows[:, 20] = fitted[3].detach().cpu().numpy()
    rows[:, 21:24] = math.log(0.12)
    rows[:, 24] = 1  # quaternion wxyz
Open the deployed source snapshot ↗
public/math/trace.mjsL151–160

The teaching encoder writes the same little-endian property sequence.

export function encodePly(records) {
  const header = new TextEncoder().encode(
    'ply\nformat binary_little_endian 1.0\nelement vertex ' + records.length + '\n' +
    properties.map(name => 'property float ' + name + '\n').join('') + 'end_header\n');
  const output = new Uint8Array(header.length + records.length * 32 * 4);
  output.set(header);
  const view = new DataView(output.buffer);
  records.forEach((row, i) => row.forEach((value, j) =>
    view.setFloat32(header.length + (i * 32 + j) * 4, value, true)));
  return output;
Open the deployed source snapshot ↗

CHECK YOUR UNDERSTANDING

Can you predict the result?

The file stores scale_0 = ln(0.2). Which runtime scale is correct?

This is your own review mark. You can remove it at any time.

Go deeper with primary sources

Spacetime Gaussian Feature Splatting · paper ↗Full mathematical derivation ↗