OpenGL の圧縮テクスチャ (2) 法線圧縮

ノーマルマップの圧縮フォーマットは 3DC が有名です。
Tangent Space の法線マップの場合 z の符号が不要なので (x,y,z) のうち
x,y のみ保存しておけば z= sqrt( 1- (x*x + y*y) ) で値が求まります。

上記の通りシェーダー側に多少追加コードが必要となるものの、RGB8 24bpp
ではなく LA8/RG8 など 16bpp の画像に保存することができます。

さらに DXT5 (8bpp) の color, alpha を独立した 2チャンネルとみなして
法線圧縮する手法 (DXT5n) があります。その応用で DXT5 の alpha 圧縮の構造を
用いて独立 2チャンネルを格納するのが 3DC です。
同じように 1 チャンネルの 4bpp フォーマットもあります。

Block Compression (Direct3D 10)

最近 OpenGL の GPU で見かける latc, rgtc も同様の構造を持った 1,2 チャンネル
圧縮フォーマットのようです。
3DC が Direct3D 10 以降 DXGI で BC4, BC5 と呼ばれているのと同様に、
OpenGL で定義された呼び方だと思われます。

ATI            DX9      DX10/DXGI   OpenGL ES    OpenGL
------------------------------------------------------------
3DC_X  4bpp    ATI1     BC4         LATC1        LATC1/RGTC1
3DC_XY 8bpp    ATI2     BC5         LATC2        LATC1/RGTC2
DX10/DXGI             FourCC  OpenGL
-----------------------------------------------------------------------------
DXGI_FORMAT_BC4_UNORM "BC4U"  GL_COMPRESSED_RED_RGTC1_EXT              0x8dbb
DXGI_FORMAT_BC4_SNORM "BC4S"  GL_COMPRESSED_SIGNED_RED_RGTC1_EXT       0x8dbc
DXGI_FORMAT_BC5_UNORM "ATI2"  GL_COMPRESSED_RED_GREEN_RGTC2_EXT        0x8dbd
DXGI_FORMAT_BC5_SNORM "BC5S"  GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8dbe

LATC と RGTC の違いはチャンネルへの展開方法だけです。
RGTC は 3DC や BC5 と互換性があります。
その代わり LATC は DXT5n とシェーダーコードを共有できます。

vec4  tex_normal= texture2D( NormalMap, otexcoord );

// RGTC unsigned, 3DC_XY, RG8
tex_normal.xy= tex_normal.xy * 2.0 - 1.0;
tex_normal.z= sqrt( 1.0- dot( tex_normal.xy, tex_normal.xy ) );

// LATC unsigned, DXT5n, LA8
tex_normal.xy= tex_normal.yw * 2.0 - 1.0;
tex_normal.z= sqrt( 1.0- dot( tex_normal.xy, tex_normal.xy ) );

RADEON (GL4.1) の場合いくつか注意点があります。

glGetIntegerv( GL_COMPRESSED_TEXTURE_FORMATS, lists )
が列挙を返してきません。代わりに Extension String の
glGetStringi( GL_EXTENSIONS, i ) で判定する必要があります。
また GL_ATI_texture_compression_3dc があっても OpenGL ES 2.0 と違い
rgtc の方を使います。
つまり GL_3DC_XY ではなく GL_COMPRESSED_RED_GREEN_RGTC2_EXT 。

// GL_EXT_texture_compression_latc
GL_COMPRESSED_LUMINANCE_LATC1_EXT              0x8C70
GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT       0x8C71
GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT        0x8C72
GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73

// GL_EXT_texture_compression_rgtc
GL_COMPRESSED_RED_RGTC1_EXT                    0x8DBB
GL_COMPRESSED_SIGNED_RED_RGTC1_EXT             0x8DBC
GL_COMPRESSED_RED_GREEN_RGTC2_EXT              0x8DBD
GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT       0x8DBE

OpenGL ES 2.0 GPU の場合 Adreno (ATI系) が 3DC、Tegra2 が LATC に対応
しています。
利用可能なカラー圧縮、法線圧縮フォーマットをまとめると下記の通りです。

          COLOR  COLOR-EA  COLOR-IA  NORMAL   NORMAL-S  1ch
--------------------------------------------------------------
PowerVR   PVRTC  --        PVRTC-A   --       --        --
Adreno    ATC    ATC-A     ATC-I     3DC_XY   --        3DC_X
Tegra     DXT1   DXT3      DXT5      LATC2    LATC2-S   LATC1
ZMS       DXT1   DXT3      DXT5      (DXT5n)  --        --
Mali      ETC1   --        --        --       --        --

対応していない GPU は非圧縮 LA8 で代用しなければなりません。
圧縮に対応していても RG(3DC) と LA でシェーダーを完全に共有するのは
難しそうです。

関連エントリ
Android OpenGL ES 2.0 の圧縮テクスチャ