TemporalAA
Edges refined past MSAA by accumulating jittered frames.
- Run
swift run --package-path Examples Example-3D-Effects-TemporalAA- Source
- Examples/3D/Effects/TemporalAA/Sketch.swift
import Ollin
/// Temporal anti-aliasing: edges refined past MSAA by accumulating jittered frames.
///
/// The scene is deliberately hostile to fixed-position anti-aliasing: thin
/// bright rods at shallow tilts, a wire trellis, a glinting sphere. MSAA
/// samples each pixel at the same eight positions every frame, so a
/// near-horizontal edge quantizes into visible steps that crawl as the camera
/// drifts. With `temporalAntialiasing()` on, the renderer nudges the camera's
/// projection by a different sub-pixel offset each frame and folds the frames
/// into a running average, so the same edges settle into clean gradients and
/// the crawling stops; the toggle makes the comparison one keypress. Exports
/// stay deterministic: a headless frame renders the scene several times at
/// fixed offsets and averages them, so a video of this sketch cannot flicker.
@main
final class TemporalAA: Sketch {
@Param(icon: "sparkles", group: "Image")
var temporalAA = true
/// Movers only: with this off, the orbiting bar falls back to the
/// conservative history blend and its thin edges stay rawer while it moves;
/// with it on, `withMotion` hands the renderer its exact screen motion and
/// the edges keep their accumulated refinement mid-flight.
@Param(icon: "arrow.triangle.swap", group: "Image")
var exactMotion = true
override func draw() {
background(Color(white: 0.045))
cameraShowcase(.sway(period: 40), target: Vector3(0, 1.2, 0),
radius: 7, elevation: 0.18, fieldOfView: .pi / 3.6)
ambientLight(Color(white: 0.10))
directionalLight(.white, direction: Vector3(-0.4, -0.9, -0.5), intensity: 0.95)
if temporalAA { temporalAntialiasing() }
// The trellis: thin bright rods at shallow angles, the worst case for
// fixed sample positions and the best showcase for the jitter average.
fill(Color(white: 0.92))
for i in 0..<9 {
withState {
translate(0, 0.25 + Double(i) * 0.28, 0)
rotate(0.03 + Double(i) * 0.011, axis: .unitZ)
drawBox(width: 5.4, height: 0.030, depth: 0.045)
}
}
for i in 0..<11 {
withState {
translate(-2.5 + Double(i) * 0.5, 1.35, -0.02)
rotate(0.06, axis: .unitX)
drawBox(width: 0.030, height: 2.7, depth: 0.045)
}
}
// A glinting sphere: its specular highlight shimmers under motion
// without the accumulation, and holds steady with it.
withState {
fill(Color(hex: 0xC05A3E))
material(.dielectric(roughness: 0.3))
translate(1.7, 0.85, 1.0)
drawSphere(radius: 0.62)
}
// A world-space mover: a thin bright bar orbiting the trellis. Camera
// motion reprojects from depth already, but this bar moves on its own,
// so only `withMotion` gives its history the exact place to look.
let orbit = {
self.withState {
self.fill(Color(white: 0.95))
self.rotate(self.time * 0.35, axis: .unitY)
self.translate(2.6, 1.6, 0)
self.rotate(0.10, axis: .unitZ)
self.drawBox(width: 1.6, height: 0.028, depth: 0.05)
}
}
if exactMotion {
withMotion("orbiter", orbit)
} else {
orbit()
}
withState {
fill(Color(white: 0.30))
translate(0, -0.06, 0)
drawBox(width: 13, height: 0.12, depth: 13)
}
drawCaption("temporalAntialiasing() \(temporalAA ? "on" : "off") - toggle it in the inspector")
}
}