Compressed Texture.

A block-compressed texture stays compressed in GPU memory, so it takes a fraction of the space of the same image as RGBA. SimVX loads the portable UASTC encoding from a KTX2 file, and a .ktx2 path goes wherever any other image path does: here it is the albedo_map of a Material on a spinning cube.

▶ Run in browser

Tags: 3d graphics textures compressed

::

Material(albedo_map=Path(__file__).parent / "assets" / "uastc_quadrants.ktx2")

UASTC is a source format, not one a GPU samples directly, so the engine transcodes it when the texture loads. On the desktop it asks the device which block family it samples and picks BC7, then ASTC 4x4, then ETC2; in the browser the same choice is made for the browser’s GPU. A device that supports none of them gets the top mip level decoded to plain RGBA instead. The scene never changes: it names the file and the engine chooses the format.

The fixture assets/uastc_quadrants.ktx2 is a 64x64 sRGB texture of red, green, blue and yellow quadrants with a full mip chain, so the cube’s faces also exercise mip sampling as it turns. You would normally make such a file with the Khronos tools, toktx --t2 --uastc --genmipmap out.ktx2 in.png; this repository ships no UASTC encoder, so assets/_generate_uastc_fixture.py packs this one by hand.

Source

 1# /// simvx
 2# tags = ["graphics", "textures", "compressed"]
 3# screenshot_frame = 30
 4# ///
 5"""Compressed Texture.
 6
 7A block-compressed texture stays compressed in GPU memory, so it takes a fraction of the space of
 8the same image as RGBA. SimVX loads the portable UASTC encoding from a KTX2 file, and a
 9``.ktx2`` path goes wherever any other image path does: here it is the ``albedo_map`` of a
10``Material`` on a spinning cube.
11
12::
13
14    Material(albedo_map=Path(__file__).parent / "assets" / "uastc_quadrants.ktx2")
15
16UASTC is a source format, not one a GPU samples directly, so the engine transcodes it when the
17texture loads. On the desktop it asks the device which block family it samples and picks BC7, then
18ASTC 4x4, then ETC2; in the browser the same choice is made for the browser's GPU. A device that
19supports none of them gets the top mip level decoded to plain RGBA instead. The scene never changes:
20it names the file and the engine chooses the format.
21
22The fixture ``assets/uastc_quadrants.ktx2`` is a 64x64 sRGB texture of red, green, blue and yellow
23quadrants with a full mip chain, so the cube's faces also exercise mip sampling as it turns. You
24would normally make such a file with the Khronos tools, ``toktx --t2 --uastc --genmipmap out.ktx2
25in.png``; this repository ships no UASTC encoder, so ``assets/_generate_uastc_fixture.py`` packs this
26one by hand.
27"""
28
29from pathlib import Path
30
31from simvx.core import Anchor, Camera3D, CanvasLayer, DirectionalLight3D, Label, Material, Mesh, MeshInstance3D, Node
32from simvx.graphics import App
33
34TEXTURE = Path(__file__).parent / "assets" / "uastc_quadrants.ktx2"
35
36
37class CompressedTextureScene(Node):
38    def on_ready(self):
39        self.add_child(Camera3D(position=(0, -4, 1.5), look_at=(0, 0, 0), up=(0, 0, 1)))
40        self.add_child(DirectionalLight3D(direction=(-0.4, 1.0, -0.6)))
41        self.cube = self.add_child(MeshInstance3D(mesh=Mesh.box(), material=Material(albedo_map=TEXTURE)))
42
43        hud = self.add_child(CanvasLayer())
44        hud.add_child(Label("UASTC .ktx2 albedo, transcoded for this GPU", anchor=Anchor.TOP_LEFT, inset=12))
45
46    def on_update(self, dt):
47        self.cube.rotate_z(0.6 * dt)
48        self.cube.rotate_x(0.3 * dt)
49
50
51if __name__ == "__main__":
52    App(title="Compressed Texture", width=1280, height=720).run(CompressedTextureScene())