TAAU

temporal upsampling reconstructs a sharp image from a half-resolution render.

▶ Run in browser

Tags: 3d taa taau render-scale quality post-processing

With render_scale below 1.0 the scene renders at a fraction of the window pixels and is normally upscaled bilinearly (soft edges, see render_scale.py). Enabling TAA at a reduced scale upgrades that upscale to TAAU (temporal upsampling): the TAA resolve writes at the full output resolution, and because every frame is rendered with a different sub-pixel jitter, the accumulated history recovers detail between the low-res pixels. The result is markedly sharper than the plain bilinear upscale at the same cost per rendered pixel.

The scene is the render-scale pillar fence: thin verticals that soften badly under bilinear upscaling and resolve back to crisp lines once TAAU has accumulated a few frames. Toggle TAA off (T) to compare against the bilinear baseline at the same render scale.

Usage: uv run python examples/features/3d/taau.py

Controls: T - toggle TAA (TAAU <-> plain bilinear upscale) 1 / 2 / 3 / 4 - render_scale 0.25 / 0.5 / 0.75 / 1.0 Escape - quit

Source

  1"""TAAU: temporal upsampling reconstructs a sharp image from a half-resolution render.
  2
  3With ``render_scale`` below 1.0 the scene renders at a fraction of the window
  4pixels and is normally upscaled bilinearly (soft edges, see render_scale.py).
  5Enabling TAA at a reduced scale upgrades that upscale to TAAU (temporal
  6upsampling): the TAA resolve writes at the full output resolution, and because
  7every frame is rendered with a different sub-pixel jitter, the accumulated
  8history recovers detail between the low-res pixels. The result is markedly
  9sharper than the plain bilinear upscale at the same cost per rendered pixel.
 10
 11The scene is the render-scale pillar fence: thin verticals that soften badly
 12under bilinear upscaling and resolve back to crisp lines once TAAU has
 13accumulated a few frames. Toggle TAA off (T) to compare against the bilinear
 14baseline at the same render scale.
 15
 16# /// simvx
 17# tags = ["3d", "taa", "taau", "render-scale", "quality", "post-processing"]
 18# screenshot_frame = 48
 19# ///
 20
 21Usage:
 22    uv run python examples/features/3d/taau.py
 23
 24Controls:
 25    T             - toggle TAA (TAAU <-> plain bilinear upscale)
 26    1 / 2 / 3 / 4 - render_scale 0.25 / 0.5 / 0.75 / 1.0
 27    Escape        - quit
 28"""
 29
 30from simvx.core import (
 31    Camera3D,
 32    DirectionalLight3D,
 33    Input,
 34    InputMap,
 35    Key,
 36    Material,
 37    Mesh,
 38    MeshInstance3D,
 39    Node,
 40    Text2D,
 41    WorldEnvironment,
 42)
 43from simvx.graphics import App
 44
 45WIDTH, HEIGHT = 1280, 720
 46
 47_SCALES = {"scale_025": 0.25, "scale_050": 0.5, "scale_075": 0.75, "scale_100": 1.0}
 48
 49
 50class TAAUScene(Node):
 51    def on_ready(self):
 52        InputMap.add_action("quit", [Key.ESCAPE])
 53        InputMap.add_action("toggle_taa", [Key.T])
 54        InputMap.add_action("scale_025", [Key.KEY_1])
 55        InputMap.add_action("scale_050", [Key.KEY_2])
 56        InputMap.add_action("scale_075", [Key.KEY_3])
 57        InputMap.add_action("scale_100", [Key.KEY_4])
 58
 59        # Half-resolution render, temporally upsampled by the TAA resolve.
 60        self.env = self.add_child(WorldEnvironment(render_scale=0.5, taa_enabled=True))
 61
 62        self.add_child(Camera3D(position=(0, 3.2, 9.0), look_at=(0, 1.2, 0), up=(0, 1, 0)))
 63        sun = self.add_child(DirectionalLight3D(intensity=2.2))
 64        sun.direction = (-0.5, -1.0, -0.4)
 65
 66        # Ground slab.
 67        self.add_child(
 68            MeshInstance3D(
 69                mesh=Mesh.cube(1.0),
 70                material=Material(colour=(0.55, 0.55, 0.6, 1.0), roughness=0.9),
 71                position=(0, -0.25, 0),
 72                scale=(16.0, 0.5, 16.0),
 73            )
 74        )
 75        # A fence of thin pillars: high-frequency verticals that bilinear
 76        # upscaling blurs and TAAU resolves back to crisp lines.
 77        for i in range(-5, 6):
 78            self.add_child(
 79                MeshInstance3D(
 80                    mesh=Mesh.cube(0.18),
 81                    material=Material(colour=(0.85, 0.35, 0.2, 1.0), roughness=0.5),
 82                    position=(i * 1.1, 1.4, -3.0),
 83                    scale=(1.0, 15.0, 1.0),
 84                )
 85            )
 86        self.add_child(
 87            MeshInstance3D(
 88                mesh=Mesh.sphere(0.8),
 89                material=Material(colour=(0.3, 0.7, 1.0, 1.0), roughness=0.3),
 90                position=(0, 1.3, 0.5),
 91            )
 92        )
 93        self.add_child(
 94            MeshInstance3D(
 95                mesh=Mesh.cube(1.1),
 96                material=Material(colour=(0.35, 0.75, 0.4, 1.0), roughness=0.35),
 97                position=(2.8, 0.55, 1.6),
 98            )
 99        )
100
101        self.label = self.add_child(Text2D(text="", position=(20, 20), font_scale=1.8))
102        self._update_label()
103
104    def _update_label(self):
105        mode = "TAAU (temporal upsample)" if self.env.taa_enabled else "bilinear upscale"
106        if self.env.render_scale == 1.0:
107            mode = "TAA (native)" if self.env.taa_enabled else "native"
108        # Two lines so the controls hint survives narrow windows instead of
109        # being clipped off the right edge.
110        self.label.text = f"render_scale = {self.env.render_scale}  |  {mode}\nT: toggle TAA    1-4: render scale"
111
112    def on_update(self, dt):
113        if Input.is_action_pressed("quit"):
114            self.app.quit()
115            return
116        if Input.is_action_just_pressed("toggle_taa"):
117            self.env.taa_enabled = not self.env.taa_enabled
118            self._update_label()
119        for action, scale in _SCALES.items():
120            if Input.is_action_just_pressed(action) and self.env.render_scale != scale:
121                self.env.render_scale = scale
122                self._update_label()
123
124
125def main():
126    App(width=WIDTH, height=HEIGHT, title="SimVX - TAAU Temporal Upsampling").run(TAAUScene())
127
128
129if __name__ == "__main__":
130    main()