TAAU¶
temporal upsampling rebuilds a sharp image from a low-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’s
pixels and the tonemap pass upscales it bilinearly, which softens every edge
(see render_scale.py). Turn on TAA at the same scale and the upscale
becomes TAAU, temporal upsampling:
env = WorldEnvironment(render_scale=0.5, taa_enabled=True)
The TAA resolve then writes at the full window resolution. Each frame renders
with a different sub-pixel jitter, so the accumulated history fills in detail
between the low-resolution pixels, and after a few frames the image is far
sharper than the bilinear upscale for the same number of shaded pixels. At
render_scale = 1.0 the same switch is ordinary TAA at native resolution.
The fence of thin pillars is where the difference shows: bilinear upscaling
blurs the verticals and TAAU resolves them back to crisp lines. Toggle TAA to
compare the two at the same scale. Each button is Button(action=name), so
it presses that action’s key and shares the key’s handler; a ButtonGroup
keeps one scale button checked.
Controls: T or TAA button - toggle TAA (TAAU or plain bilinear upscale) 1 / 2 / 3 / 4 or buttons - render_scale 0.25 / 0.5 / 0.75 / 1.0
Source¶
1# /// simvx
2# tags = ["3d", "taa", "taau", "render-scale", "quality", "post-processing"]
3# screenshot_frame = 48
4# ///
5"""TAAU: temporal upsampling rebuilds a sharp image from a low-resolution render.
6
7With ``render_scale`` below 1.0 the scene renders at a fraction of the window's
8pixels and the tonemap pass upscales it bilinearly, which softens every edge
9(see ``render_scale.py``). Turn on TAA at the same scale and the upscale
10becomes TAAU, temporal upsampling:
11
12 env = WorldEnvironment(render_scale=0.5, taa_enabled=True)
13
14The TAA resolve then writes at the full window resolution. Each frame renders
15with a different sub-pixel jitter, so the accumulated history fills in detail
16between the low-resolution pixels, and after a few frames the image is far
17sharper than the bilinear upscale for the same number of shaded pixels. At
18``render_scale = 1.0`` the same switch is ordinary TAA at native resolution.
19
20The fence of thin pillars is where the difference shows: bilinear upscaling
21blurs the verticals and TAAU resolves them back to crisp lines. Toggle TAA to
22compare the two at the same scale. Each button is ``Button(action=name)``, so
23it presses that action's key and shares the key's handler; a ``ButtonGroup``
24keeps one scale button checked.
25
26Controls:
27 T or TAA button - toggle TAA (TAAU or plain bilinear upscale)
28 1 / 2 / 3 / 4 or buttons - render_scale 0.25 / 0.5 / 0.75 / 1.0
29"""
30
31from simvx.core import (
32 Anchor,
33 Button,
34 ButtonGroup,
35 Camera3D,
36 CanvasLayer,
37 DirectionalLight3D,
38 HBoxContainer,
39 Key,
40 Label,
41 Material,
42 Mesh,
43 MeshInstance3D,
44 Node,
45 WorldEnvironment,
46 on_input,
47)
48from simvx.graphics import App
49
50SCALES = {"scale_25": 0.25, "scale_50": 0.5, "scale_75": 0.75, "scale_100": 1.0}
51
52
53class TAAU(Node):
54 input_context = {
55 "taa": [Key.T],
56 "scale_25": [Key.KEY_1],
57 "scale_50": [Key.KEY_2],
58 "scale_75": [Key.KEY_3],
59 "scale_100": [Key.KEY_4],
60 }
61
62 def on_ready(self):
63 self.env = self.add_child(WorldEnvironment(render_scale=0.5, taa_enabled=True))
64 self.add_child(Camera3D(position=(0, 3.2, 9.0), look_at=(0, 1.2, 0)))
65 self.add_child(DirectionalLight3D(intensity=2.2, direction=(-0.5, -1.0, -0.4)))
66
67 ground = Material(colour=(0.55, 0.55, 0.6), roughness=0.9)
68 self.add_child(MeshInstance3D(mesh=Mesh.box((16, 0.5, 16)), material=ground, position=(0, -0.25, 0)))
69 pillar, brick = Mesh.box((0.18, 2.7, 0.18)), Material(colour=(0.85, 0.35, 0.2), roughness=0.5)
70 for i in range(-5, 6):
71 self.add_child(MeshInstance3D(mesh=pillar, material=brick, position=(i * 1.1, 1.4, -3.0)))
72 blue = Material(colour=(0.3, 0.7, 1.0), roughness=0.3)
73 self.add_child(MeshInstance3D(mesh=Mesh.sphere(0.8), material=blue, position=(0, 1.3, 0.5)))
74 green = Material(colour=(0.35, 0.75, 0.4), roughness=0.35)
75 self.add_child(MeshInstance3D(mesh=Mesh.box(1.1), material=green, position=(2.8, 0.55, 1.6)))
76
77 hud = self.add_child(CanvasLayer())
78 self.status = hud.add_child(Label(anchor=Anchor.TOP_LEFT, inset=16, font_size=28))
79 bar = hud.add_child(HBoxContainer(anchor=Anchor.BOTTOM_LEFT, inset=16))
80 self.taa_button = bar.add_child(Button("TAA", action="taa", checked=True))
81 group = ButtonGroup()
82 self.buttons = {name: bar.add_child(Button(str(s), action=name, group=group)) for name, s in SCALES.items()}
83 self.buttons["scale_50"].checked = True
84 self.show_mode()
85
86 @on_input("taa")
87 def toggle_taa(self, _event):
88 self.env.taa_enabled = not self.env.taa_enabled
89 self.show_mode()
90
91 @on_input(tuple(SCALES))
92 def set_scale(self, event):
93 self.env.render_scale = SCALES[event.action]
94 self.buttons[event.action].checked = True
95 self.show_mode()
96
97 def show_mode(self):
98 taa, scale = self.env.taa_enabled, self.env.render_scale
99 if scale == 1.0:
100 mode = "TAA (native)" if taa else "native"
101 else:
102 mode = "TAAU (temporal upsample)" if taa else "bilinear upscale"
103 self.taa_button.checked = taa
104 self.status.text = f"render_scale = {scale} | {mode}"
105
106
107if __name__ == "__main__":
108 App(title="TAAU Temporal Upsampling", width=1280, height=720).run(TAAU())