ATFの特徴

ATF(Adobe Texture Format)はAdobeが作成した圧縮テクスチャーのフォーマットです。もともとはStage3Dという、Adobe Flash Player上からGPUを使用して描画できる機能のために作成されたフォーマットですが、ファイルの中身は通常の圧縮テクスチャーが格納されているためFlashでなくとも利用できます。

前述の通りプラットフォームごとに対応する形式が異なるため、マルチプラットフォームで取り回しにくい圧縮テクスチャーですが、Adobeはなんとこれらを1つのファイルにまとめました。ATFを使えば複数の圧縮テクスチャーを1つのファイルで扱えるため、プラットフォームを意識することなく開発できるメリットがあります。もともと、Adobe Flash PlayerやAdobe AIRはプラットフォームの差を吸収し、開発者に意識させないつくりのため、圧縮テクスチャーに関してもその考えを踏襲しています。

DXT1/DXT5、PVRTC、ETC1、ETC2のすべてのテクスチャーを1つのATFファイルに含められますが、「モバイルのみの対応でいいためDXT1/DXT5は省きたい」といったケースにも柔軟に対応できます。詳しくは下記の資料を参照ください。

※該当記事は古いバージョンのATFの説明のため、ETC2についての記載がありません。最新の情報については英語記事 「Introducing compressed textures with the ATF SDK | Adobe Developer Connection」 を参照ください。

ATFファイルの作成方法

ATFファイルを作成するにはATFツールを使用します。ATFツールは最新のAdobe AIR SDKに含まれています。ダウンロードしたAIR SDK直下のatftoolsフォルダにいくつかのツールが提供されていますが、主に使用するのは以下の2つです。

①png2atf
png2atfは、PNG画像からATF圧縮テクスチャーを作成するコマンドラインツールです。変換するPNG画像を用意するだけで簡単にATFファイルを作成できます。基本的な使い方は-cオプションをつけて実行します。入力するPNG画像のサイズは、各辺がPOT(Power of two、2のべき乗)となっている必要があるので注意してください。

png2atf -c -i inputFileName.png -o outputFileName.atf

iOS向けにPVRTC形式のみ含めたい場合は-cオプションの引数にpを指定します。

png2atf -c p -i inputFileName.png -o outputFileName.atf

-cオプションの引数は、,(カンマ)で区切ることでATFファイルに含める形式を任意の組み合わせで指定できます。たとえば、モバイル(iOS、Android)向けにPVRTC形式とETC1のみ含めたい場合は-cオプションにp,eを指定します。

png2atf -c p,e -i inputFileName.png -o outputFileName.atf

②ATFViewer
ATFViewerは、ATFファイルを読み込んで中に含められた各形式のテクスチャー画像やミップマップを表示するGUIツールです。圧縮テクスチャーの画質の確認に使います。atftools\docs\Readme.txtにある通り、起動するには別途QT SDKのインストールが必要です。

ATFツールの詳しい使い方は下記の資料を参照ください。

※該当記事は古いバージョンのATFの説明のため、ETC2についての記載がありません。最新の情報については英語記事 「ATF SDK user’s guide | Adobe Developer Connection」 を参照ください。

WebGLでの使用

WebGLでATFファイルを使用する場合、まずはファイルをUint8Arrayのバイト列として読み込みます。

fetch(filePath).then(
  (response) => response.arrayBuffer())
  .then((arrayBuffer) => {
    const data = new Uint8Array(arrayBuffer);
    // 以下パース処理
  });

次に読み込んだデータをパースします。ATFファイルのバイナリフォーマットは下記を参照します。

ATFファイルは、おおまかにテクスチャーの情報が格納されたヘッダー部と実際のテクスチャーデータが格納されたデータ部に別れます。
①ヘッダー部

FieldTypeComment
SignatureU8[3]‘ATF’固定
ReservedU321バイト目:0x00固定
2バイト目:0x00固定
3バイト目:下位1bitは-eオプションの使用有無、
残り7bitは-nオプションで
ミップマップを指定した場合のミップマップ数
4バイト目:0xFF固定
VersionU8ATFファイルフォーマットのバージョン
※ 2018年5月現在のバージョンは3
LengthU32Field~Lengthまでを除いたこのATFファイルのバイト数
CubemapUB[1]cubeテクスチャーであるかの指定
FormatUB[7]データ部のフォーマット
Log2WidthU8テクスチャーの高さのlog2(最大12)
ATFテクスチャーの各辺はPOTである必要があるため、
実質幅の定義に等しい
Log2HeightU8テクスチャーの幅のlog2(最大12)
CountU8テクスチャー1枚毎のミップマップ数(最大13)

②データ部
データ部は、複数の形式のテクスチャーが[バイト数,データ]の順に格納されたブロックがミップマップ数(ヘッダー部のCount)分繰り返されます。さらにcubeテクスチャーの場合、上記が[Left, Right, Bottom, Top, Back, Front]の順に6面分繰り返されます。

ブロックの定義はヘッダー部のFormatによって異なり、たとえばFormat=3(RAW Compressed)の場合は下記の仕様となります。

FieldTypeComment
DXT1ImageDataLengthU32DXT1データのバイト数
DXT1ImageDataU8[DXT1ImageDataLength]DXT1データ
PVRTCImageDataLengthU32PVRTCデータのバイト数
PVRTCImageDataU8[PVRTCImageDataLength]PVRTCデータ
ETC1ImageDataLengthU32ETC1データのバイト数
ETC1ImageDataU8[ETC1ImageDataLength]ETC1データ
ETC2RgbImageDataLengthU32ETC2データのバイト数
ETC2RgbImageDataU8[ETC2RgbImageDataLength]ETC2データ

※ETC2データに関しては今回使用していません。

バイナリフォーマットに従って順にデータを読んでいき、実際のテクスチャーデータ(RAW data)をUint8Arrayの配列として取得します。配列の切り出しにはUint8Array.subarray()を使えば無駄なメモリのコピーがされません。

// PVRTCImageData U8[PVRTCImageDataLength]
// RAW PVRTC data

// startByteからpvrtcImageDataLength分の長さのデータをUint8Arrayとして切り出す
const pvrtcImageRawData = data.subarray(startByte, startByte + pvrtcImageDataLength);

ATFファイルから取得したRAW dataは、前述のWebGLRenderingContext.compressedTexImage2D()の第七引数としてそのまま使用できます。

最後に

WebGLにおいて圧縮テクスチャーの使用はメモリ容量、速度の両面で有効な手段です。画像によっては画質の劣化に気をつける必要がありますが、使いこなせれば特にリソースの少ないモバイル対応で力を発揮します。プラットフォームごとに異なる形式のテクスチャーを用意して使用する手間も、ATFを使えば解決するのでぜひ試してみてください。