NEUROMANTIC

自分でC/C++/UE4/Graphics/ゲームなどをやったことをメモするブログ

「Understaning BCn Texture Compression Formats」を読んでメモ

www.reedbeta.com

  • GPUで支援しているBCnというテクスチャフォーマットはBC1からBC7まである。
  • BCnテクスチャフォーマットらの特徴は、読み込みをする時で圧縮されたデータが解凍されるのではなくて、GPUからあるテクセルの部分を使うときだけその一部分のデータが解凍されて使われる。そうすることによってテクスチャのキャッシュの負荷を省けることが出来るし、最終的には処理速度が上がる。

なぜテクスチャを圧縮するのか?

  • ハードウェアのRAMまたはメモリが収容できる容量が増えつつも、テクスチャを圧縮して使うことはさんざんある。
    • 今時期のゲームは、AAAゲームの場合には少なくとも50GB異常になるゲームが多い。そしてテクスチャも2K以上で使っているゲームも多いし、単純に非圧縮のテクスチャを1000枚以上も使うことになると、ゲームの容量がものすごくでかくなる。そのため、圧縮テクスチャは今でも良く使われるそうだ。
    • BCnの圧縮ではんくて、ETCのようなモバイル系のテクスチャアルゴリズムもある。モバイルゲームの場合には容量が少ないため、最大限にテクスチャの容量を抑えることがほしくなる。
    • 現代のゲームでは3Dモデル一個に、テクスチャは4枚、または5枚が必要となる。
  • GPUの発展にもかかわらず、シェーダーでテクスチャをサンプリングするために必要となる費用はどんどん高くなっている。なぜなら、GPUのプロセッサーの速度は早くなりつつも、VRAM(メモリ)の接近速度は昔とほぼイマイチだそうだ。そして単純にメモリとプロセッサーだけがあった昔とは違って、今はあらゆる要素が関与しているため、接近速度の差は大きくなっているらしい。
    • なので、テクスチャを圧縮して接近させるほうが処理速度として速くなる。
  • 様々な圧縮テクスチャが研究・開発されている。

Block Compression(ブロック圧縮)

  • BCnフォーマットは4x4ブロックでピクセルたとを表現する。そして、ブロックの中にはGPUからデコードされるデータが入っている。
  • 各BCnのテクスチャフォーマットはブロックのサイズが固定している。普通8か、16バイトになる。従って、ヘッダーファイルなどを除けば非圧縮テクスチャとの容量差は8:1、16:1になる。
  • ブルック、構造のレイアウトはGPUが接近速度を速くし、処理速度を短くするために設計された。
    • よって、普通のテクスチャみたいではなく、あるブロックがGPUから接近すると、GPUから圧縮の解除がされて、周りだけまでテクスチャキャッシュに載せられる。
    • 参照の局所性まで捉えようとしている。

Endpoints and Indices

f:id:neuliliilli:20190523191534p:plain

  • BCnフォーマットの共通的な捉え方は、テクスチャをブロックに分けてみると、ブロック中のピクセルの色の変動はあんまり変わらないということだ。上の図で、ブロック中のピクセルのカラーがあんまり変わらないことが分かる。
  • BCnは、ブロックごとに小さいカラーパレットで分けられている。カラーパレットは数少ない色しか選べない。そしてピクセルはそのカラーパレットの色番号(Index)が代わりに指定される。
  • カラーパレットは、RGB領域で均一に分布されていると仮定して、そのカラーパレットの最初となる色と最後となる色だけがデータ化される。(GPUでこれを解凍して色を参照する)
    • 他の色はGPUから圧縮解除する時に、over演算子でブレンディングされて得られる。
    • この最初・最後の色をEndpointという。
  • よって、BCnの各ブロックはこれらを持っている。
    1. Endpoint
    2. Endpointから得られるカラーパレットのインデックスが指定されたピクセルたち。
  • したがってブロックに3つの色領域が収まっているテクスチャは、この圧縮フォーマットに向いてない。
    • Most of the BCn formats will give poor-quality results anywhere that three very different colors are present in a single block. For example, a block containing a mix of red, green and blue pixels cannot be represented using the simpler BCn formats, because red, green, and blue do not lie along a straight line in RGB space.

    • ただし現在ではBC7というフォーマットが、2つのカラーパレットを支援しているため、場合によって良いかも?と。
    • ノーマルマップもBCnに向いてない。

BC1

  • D3DではDXT1と呼ばれたそうだ。
  • RGBデータ・二値アルファを支援する。即ち、アルファは0か1しか選べられない。
  • ブロックは「8Byte/4x4ピクセル」を成している。2つのEndpointが各自2バイトとして(5・6・5ビット/各チャンネル)セーブされている。インデックスは一ピクセルごとに2Bitを消耗する。
  • 色の変化が大きくないと非圧縮との差はあんまり見えないが、そうでない場合には他(BC4、BC7)に比べて劣化が見やすい。でも一応広く使われるそうだ。

BC1のアルファはどうやって実装する?

まず、BC1ではEndpointを作るためには、1:1ではなく、様々なケースから一つのEndpointsを得られることが出来る。これをDegenerateという。例えば、Endpointsをスワップして、2つの色が対照群と同じであればDegenerateだそうだ。

しかしアルファを実装するにはこのDegenerateを破ってから各色の順位と解釈モードを違ってして実装する必要があるらしい。例えば、5・6・5ビットのRGB色があるなら、これをただの16ビットとして扱う。例えば一番目のEndpointが二つ目より大きくと、普通の4個の色、そしてインデックスとして解釈される。しかしそうではない場合だとしたら、3つの色と残りの一つのカラーは0または255のアルファになる。

  • アルファを支援するモードがある。しかしアルファを使うと、色の劣化がもっとひどくなる短所がある。

BC4

f:id:neuliliilli:20190523200959p:plain
元記事のBC4より

  • BC4はグレースケールのイメージを圧縮するに最適化されている。「8Byte/4x4ピクセル」なのに、Endpointは8Bitで2個、圧縮解除することで8個のグレーカラーが得られる。インデックスは3Bitを使う。
  • BC1よりグレースケール面としてはだいぶ優れているので、Height、Gloss、Light、AO、Displacementマップに使える。
  • BC1みたいに2つのモードを支援する。

「DirectX 11の圧縮フォーマットBC1~BC7について(前編)」より…
BC4の圧縮データは、DirectX 9時代にATI1N(またはATI1)と呼ばれていた圧縮テクスチャ形式と基本的には同じものです。OpenGLではBC4と同様の圧縮フォーマットがRGTC(またはRGTC1)と呼ばれています。

BC2, 3, 5

  • BC2はDXT2~3の代替、BC3はDXT4~5の代替だそうだ。
  • BC2BC5BC3はブロックのサイズが16バイトだ。
    • BC2はRGBのカラー値と、4ビット精度(16階調)のアルファを表現できる。しかし、アルファを表現するために、各ピクセルに4Bitずつのアルファ値を追加的に入れなければならない。よって、アルファ値の表現部分は16バイトから8バイトを占める。ただし、なめらかなアルファのグラデーションは無理そうな気もする。
    • BC3はRGBのカラー値と多階調のアルファを表現できるように構造が設計された。BC2またはBC1とは違って、アルファもEndpoints(1バイト*2個)を持つ。そしてインデックスは、アルファに対しては3Bitを持つようだ。(アルファは6個で分けられるらしい)
    • BC5は法線マップ(ノーマルマップ)などのような2成分(2チャンネル)の情報を格納するためのものだそうだ。BC5ATI2または3Dcとしても呼ばれる。OpenGLではBC5と同様の圧縮フォーマットがRGTC(またはRGTC2)。BC5は2つのベクトル成分を記録して(x、y)zを測れる。

「DirectX 11の圧縮フォーマットBC1~BC7について(前編)」より…
BC3で圧縮すると、アルファが0で完全に透明だったピクセルのアルファ値が1以上になって、見えないはずのピクセルがうっすらと見えたり、逆に、アルファが255で完全に不透明だったピクセルのアルファ値が255未満になり、背景がうっすらと透けてしまう、などの問題が起きる場合があります。

BC6, 7

  • BC6またはBC6Hは、D3D11から追加されたフォーマットで、HDR(ハイダイナミックレンジ)のRGB画像データを格納するためのものだ。OpenGLでは、BC6Hに相当する圧縮テクスチャ形式はBPTCと呼ばれている。
    • BC6はHDRに対応させるために、HDR値を16Bitの浮動小数点に収めている。よってブロックごとに16Byteを持つ。
    • BC6のモードは14個もあり、複雑すぎる。もしかしてどんなモードがあるかみたいならLinkを見ること。
  • BC7はBC1~BC3よりも高品質な画像データを格納するためのものである。OpenGLでは、BC7に相当する圧縮テクスチャ形式はBPTCと呼ばれている。
  • BC6HBC7はパーティションというものを提供している。これは単一のブロックのピクセルが違うEndpointのカラーセグメントを使用するようにするものである。もちろんこのパーティションのBitはすでに定義されていて(パターン化)、パターンによって各ピクセルのEndpointのセットを切り替える。

BCnテクスチャがどうやって圧縮をするのかは、もっと複雑な内容となりますのでメモはしません。ただし、みたい方々がいましたら、元記事の「Compression Cleverness」欄を見ていただけます。

終わり

f:id:neuliliilli:20190523205452p:plain
http://www.reedbeta.com/blog/understanding-bcn-texture-compression-formats/#comparison-table

元記事からのBCnのフォーマットをまとめた表をアップロードします。BC6H、BC7はモードが多いため、はっきりとはしませんでしたが、大体の用途、どのような構造を持ってるかはメモを取りながら分かった気がします。

最後に、このBCnのテクスチャを圧縮・解除させるツールのリンク先を貼ります。

github.com

かなり昔のものですが、BC1~5までの圧縮・解除が出来ます。

github.com

これはオープンソースのBC7(BPTC)圧縮・解除プログラムです。

github.com

これはMITライセンスのDirectXTexの、TexConvというBCnテクスチャの変換ツールです。上の2つもいいですが、これで一つに収めて使っても構わないじゃないかなと思います。

参照

www.webtech.co.jp

www.webtech.co.jp

docs.microsoft.com

docs.microsoft.com

docs.unity3d.com