BlogKLabは、多くのスマートフォン向けゲームを開発・提供しています。スマートフォン向けゲームの開発と運用は、Webソーシャルゲームと比べて格段に複雑で、またコンシューマゲーム開発とも異なったノウハウが求められる領域もあります。このブログでは、KLabのゲーム開発・運用の中で培われた様々な技術や挑戦とそのノウハウについて、広く紹介していきます。12/19の記事です。昨年はWebGLをつかったソートを実装してみましたが今年はWebGLを使った画像圧縮を実装してみます。はじめにWebGLのみならずアプリ開発において画像のフォーマットの選択は重要です。ゲームの大部分を占める画像データはゲームのダウンロード時間に直結するため可能な限り圧縮しておきたいものです。WebGLではGPUにテクスチャをアップロードする際にはgl.texImage2Dを使用します。gl.texImage2DはTexImageSourceをアップロードできます。このTexImageSourceというのが面白くてテクスチャデータとしてHTMLImageElementが使えます。GIF/JPEG/PNGといったフォーマットだけでなくGoogleが開発した高圧縮率フォーマットであるWebPも使用可能です。HTMLVideoElementもテクスチャフォーマットとして使用できるため、動画さえもテクスチャにできます。ダウンロードサイズの削減が目的であればGIF/JPEG/PNG/WEBPから適切なフォーマットを選ぶのがよいでしょう。ビデオメモリの容量も気にしたいところで、画素あたりのビット数も削減したいところです。WebGLにおいてはPNGなどを用いた場合、1画素あたり32bit使用することが多いでしょう。その場合、1024x1024のテクスチャ1枚当たり4MByteのサイズとなります。なってくると選ばれるフォーマットはETCやPVRTCでしょう。ETC2の8bit/pixelを用いれば1024x1024のテクスチャも1/4のサイズである1MByteまで削減できます。1.0ではエクステンションのため使用できる保証がありません。2.0で使用可能とのことなので今後はETC2を積極的に使用していきたいところです。今回はこれらとは異なるアプローチで画像圧縮を試みてみました。YCgCo色空間を使用して画像の圧縮を試みている方がいらっしゃいました。人間の目はLumaに比べてChromaの変化に対して鈍感である性質を利用してChromaの情報量を落として圧縮しています。人間の目はLumaのみの画像に対してChromaの変化に鈍感であることが実感できると思います。このアイディアそのままにWebGLによる再実装を行いました。色空間を変換するシェーダRGBAをYCgCoAに変換するYCgCoとRGBの色空間は行列による変換が可能です。シェーダとも相性がよくシェーダでも行列を使用して変換を行います。+0.5]のためテクスチャに保存する際に0.5を加算します。この加算含めて4x4行列にまとめるとRGBAをYCgCoAに変換するシェーダは以下のように書けます。(A,R,B,G)のように割り当てます。変換後の画像をさらにRGBとAに分割し、RGB画像の解像度を1/4に縮小します。12bitとなります。縮小したCgCoA画像YCgCoAをRGBAに変換するYCgCoAに変換した2枚のテクスチャをシェーダで合成し、RGBAに変換します。その際にVRAMの節約のためにCgCoA画像はRGB565のテクスチャで、Y画像はAlpha8のテクスチャとしてアップロードします。image);シェーダで合成する際はCgCoに0.5を加算しているため行列をかけるまえに0.5ひいてやります。左:元画像、右:合成画像ほぼ劣化がないように見えます。こちらを参考に差分をとってみます。diff.png428.525確かに差分が発生しているので画像は劣化してはいるようです。差分画像を正規化した物がこちらです。全体的に差分が発生していることが確認できます。Chromaのビット数を削減しているので納得できる結果となりました。最後にYCgCoによる圧縮は見た目上は効果的であるということはわかりましたが、いくつかの問題点があります。1つはテクスチャフェッチが2回必要となること。テクスチャフェッチは重い処理なのでできれば少なくしたいところです。1つはアルファのみを保存する適切なフォーマットが見つからないこと。32bit深度で保存されてしまい少しもったいないです。原因の特定はできなかったのですがGPUによってはうまく描画できない例も見受けられました。ビデオメモリの節約であればETC2に望みを託す、というのが今はよいかもしれません。