こんにちは、Sleipnir 3 for Windows 開発担当の森本です。
さて、前回は TouchPaging での使用されている、半透明処理の計算量が多くて困るという話で終わったのですが、今回はその問題を解決して、その後にさらに起こる面倒くさい点について話そうと思います。
a = 0.1 * ( 1.0 - 0.5 ) + 0.5 => 0.55 r = ( 0.0 * 0.1 * ( 1.0 - 0.5 ) + 1.0 * 0.5 ) / 0.55 => 0.91 g = ( 0.0 * 0.1 * ( 1.0 - 0.5 ) + 0.0 * 0.5 ) / 0.55 => 0.00 b = ( 1.0 * 0.1 * ( 1.0 - 0.5 ) + 0.0 * 0.5 ) / 0.55 => 0.09
前回面倒だと言っていた、この式をよく観察すると dest.b * dest.a のような透明度と輝度を掛ける計算が沢山あるのが解ります。
乗算は計算時の負荷が高いので、何とか減らす方向で式を改良します。また、割り算も辛いので何とか出来無いか考えてみます。
たとえば、各色を予め透明度で乗算しておけば、乗算を減らし計算をシンプルに出来て、各色の分母と新しい透明度も同じなので、ひょっとしたら割り算も無くせるかもしれません。
struct premultiplied_pixel { float b; // 青。範囲は 0.0~a float g; // 緑。範囲は 0.0~a float r; // 赤。範囲は 0.0~a float a; // 透明度。範囲は 0.0~1.0 で 1.0 が不透明 }; pixel src2; // 転送元。ユーザーから見て手前にある pixel pixel dest2; // 転送先。ユーザーから見て奥にある pixel
これをもとに式も作り直してみます。
dest2.a = dest2.a * ( 1.0 - src2.a ) + src2.a dest2.r = dest2.r * ( 1.0 - src2.a ) + src2.r dest2.g = dest2.g * ( 1.0 - src2.a ) + src2.g dest2.b = dest2.b * ( 1.0 - src2.a ) + src2.b
おお!シンプルになりました。これぐらいならば実用的な速度で計算できそうです!
さて、今回の計算のために新しいピクセルフォーマットを作ったわけですが、この形式は一般に「乗算済みアルファ(Pre-multiplied Alpha)」と呼ばれ、特にリアルタイムで画像処理をする場合によく使われています。
しかしその割に全体としての知名度が低く、「普通の RGBA フォーマットと混同されている」のを割と見かけます。RGBフォーマットとRGBAフォーマットは透明度を無視すれば「ほぼ同じ物」と言えますが、乗算済みアルファの RGBA と、普通の RGBA の間には「互換性がなく、変換が必要」です。
そして、 この違いに関する Windows の実装がこの混乱に拍車を掛けています。
Vista 以降で Aero を有効にしている場合、トップレベルのウインドウは 同じサイズの 32bit ビットマップ (DIB) を持っているのですが、これがかなり特殊な扱いをされています。具体的には、Aero の透明部分では「乗算済みアルファ RGBA」フォーマット、不透明部分では「普通のRGB」フォーマットだとして描画されています。
一枚のビットマップのフォーマットを部分的に変えるなんて、いったいなぜこんな事に…
と頭を抱えていてもしょうがないので、(たぶん)次回は Sleipnir 3 の実装で使っている方法などを交えつつ、対処法を書いていきたいと思います。
Sleipnir の Facebook ページでは、ユーザーの方たちとのコミュニケーションや最新情報の投稿などを行なっています。よろしければいいね!してください!