PAJAMA / LEARN
← Course overview

See how pixels are made / 04 OF 12

How overlapping splats become one pixel

After this lessonCompute front-to-back transmittance, explain ordering, and map the result to GPU blending.

Look through two colored sheets of translucent film. The front sheet contributes color and hides part of the sheet behind it. A simple average cannot describe this.

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.

Vectors & weighted sums

STEP 1 / 5

Coverage is only a candidate test

Project a footprint and bound it with a rectangle. A pixel inside that rectangle is a candidate, not necessarily strongly covered. Evaluate its Gaussian weight using the inverse screen covariance and displacement from the projected center. Multiply by the evaluated opacity to get alpha.

αi=oi(t)exp⁡[−12(p−μi)TCi−1(p−μi)]\alpha_i=o_i(t)\exp[-\tfrac12(\mathbf p-\boldsymbol\mu_i)^TC_i^{-1}(\mathbf p-\boldsymbol\mu_i)]

PUT NUMBERS IN

With black background, red in front gives (0.6, 0, 0.2); blue in front gives (0.3, 0, 0.5). Contributions and residual background weights sum to 1. The lab lets you check both recurrence conventions numerically.

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.

public/learn/models.mjsL8–14

The exact arithmetic behind this lesson’s controls and worked example.

export function composite(a,b,reverse=false){
 const layers=reverse?[[b,[0,0,1],'B'],[a,[1,0,0],'A']]:[[a,[1,0,0],'A'],[b,[0,0,1],'B']];
 let remaining=1;const color=[0,0,0],weights=[];
 for(const [alpha,rgb,id] of layers){const weight=remaining*alpha;weights.push({id,weight});rgb.forEach((v,c)=>color[c]+=weight*v);remaining*=1-alpha;}
 const over=[0,0,0];for(const [alpha,rgb] of [...layers].reverse())rgb.forEach((v,c)=>over[c]=alpha*v+(1-alpha)*over[c]);
 return {color,over,weights,remaining};
}
Open the deployed source snapshot ↗
src/splat.wgslL130–136

The fragment shader emits RGB multiplied by alpha.

fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {
  let power = -0.5 * dot(input.local, input.local);
  let alpha = min(0.99, input.color_opacity.a * exp(power));
  if (alpha < 0.0039215686) {
    discard;
  }
  return vec4<f32>(input.color_opacity.rgb * alpha, alpha);
Open the deployed source snapshot ↗
src/stg_pass.rsL189–204

The host chooses premultiplied-alpha blending.

                    blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),
                    write_mask: wgpu::ColorWrites::ALL,
                })],
            }),
            primitive: wgpu::PrimitiveState {
                topology: if gpu_variant >= 2 {
                    wgpu::PrimitiveTopology::TriangleStrip
                } else {
                    wgpu::PrimitiveTopology::TriangleList
                },
                ..Default::default()
            },
            depth_stencil: depth.map(|(format, depth_compare)| wgpu::DepthStencilState {
                format,
                depth_write_enabled: Some(false),
                depth_compare: Some(depth_compare),
Open the deployed source snapshot ↗
src/stg_prepare.rsL192–204

The host establishes the draw order.

        let sort_started = web_time::Instant::now();
        if variant >= 4 {
            if variant >= 8 {
                radix11(&mut self.ordered, &mut self.scratch);
            } else {
                radix(&mut self.ordered, &mut self.scratch);
            }
        } else {
            self.ordered
                .sort_unstable_by(|a, b| b.0.total_cmp(&a.0).then(a.1.cmp(&b.1)));
        }
        self.sort_ms = sort_started.elapsed().as_secs_f64() * 1000.0;
        self.indices.clear();
Open the deployed source snapshot ↗

CHECK YOUR UNDERSTANDING

Can you predict the result?

Why can swapping two translucent layers change the color?

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

Go deeper with primary sources

3D Gaussian Splatting · paper & implementation ↗WebGPU · specification ↗Full mathematical derivation ↗