TAAU¶
temporal upsampling reconstructs a sharp image from a half-resolution render.
▶ Run in browserTags: 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()