ゲームつくろ〜質問箱
(現在 過去ログ2 を侮ヲ中)

HOME HELP 新規作成 新着記事 トピック侮ヲ 検索 過去ログ

[ 最新記事及び返信フォームをトピックトップへ ]

■1423 / inTopicNo.1)  半透明と半透明のアルファブレンドについて
  
□投稿者/ 痺れ団子 -(2008/12/15(Mon) 18:39:04)
    はじめまして、痺れ団子と申します。
    最近DirectX9(March 2008)を触り始めたばかりで、このサイトで勉強させていただいています、ありがとうございます。

    さて、今回お聞きしたいのは、
    Photoshopなどのソフトで「通常」と呼ばれるアルファブレンド方式を、DirectXで再現するにはどうしたらよいか、という事です。
    「通常」による合成の計算式は、Srcのα(0〜1)と色(0〜1)をそれぞれSa,Sc、以下同じくDestをDa,Dc、合成後をRa,Rcとすると
    Ra = Sa + (1-Sa)*Da
    Rc = (Sa*Sc + (1-Sa)*Da*Dr) / Ra //これをR,G,Bそれぞれに計算します
    となるようで、特にDaが1の時、
    Ra = 1
    Rc = Sa*Sc + (1-Sa)*Dc
    となり、DirectXでアルファブレンドするなら、
    SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
    SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
    SetRenderState(D3DRS_BLENDOP,D3DBLENDOP_ADD);
    SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
    SetRenderState(D3DRS_SRCBLENDALPHA,D3DBLEND_ONE);
    SetRenderState(D3DRS_DESTBLENDALPHA,D3DBLEND_INVSRCALPHA);
    SetRenderState(D3DRS_BLENDOPALPHA,D3DBLENDOP_ADD);
    と同じになるかと思います。

    このブレンド係数設定でいくと、例えばα付フォーマットのバックバッファをクリアして、Sprite上に半透明のテクスチャを何枚か重ね、バックバッファの内容をPNG形式のファイルに書き出した時に、最初にクリアする色が不透明(Da=1)ならば問題ありませんが、そうでないと、当然思ったようにブレンドされません。
    しかし、バックバッファを透明色でクリアし、その上に半透明のテクスチャが重なっていくような、Daが1でない状況にも対応できるブレンド係数の設定はできなさそうなので、何かよい解決策はないものかと質問させていただいた次第です。
    今私が扱っているのは、Spriteに貼り付ける"単色のテクスチャ"と"ID3DXFontによる文字"それぞれを数枚合成する2Dですので、(もし存在するのなら)この条件に特化した解決策でも構いません。

    長い割りに分かりにくい質問内容となってしまいましたが、よろしくお願いいたします。
引用返信 削除キー/
■1427 / inTopicNo.2)  Re[1]: 半透明と半透明のアルファブレンドについて
□投稿者/ IKD -(2008/12/16(Tue) 22:28:18)
http://marupeke296.com
     痺れ団子さん、ご質問頂きましてありがとうございます。
     
     レンダーステートによる半透明ポリゴンの合成をPhotoShopの「通常」、つまりレイヤー同士の重ね合わせのように計算する方法について調べましたが、これをステート設定だけで厳密に実現する方法は残念ですが無さそうです。
     
     DirectXでのいわゆる「アルファブレンド」は、
     
      R.c = S.c * S.a + D.c * ( 1 - S.a )
      R.a = S.a * S.a + D.a * ( 1 - S.a )
      
    が定番となっておりますが、これだと背景(Dest)のアルファ成分がカラーには反映されません。

     一方PhotoShopの通常ブレンドは、痺れ団子さんがお示し下さったとおりで、

      R.c = ( S.c * S.a + ( 1 - S.a ) * D.a * D.c ) / R.a
      R.a = 1 * S.a + D.a * ( 1-S.a )

    のようです(これ実は知りませんでした。確認して納得です(^-^;)。

     アルファの合成式についてはお示し頂いたように、
     
    SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
    SetRenderState(D3DRS_SRCBLENDALPHA,D3DBLEND_ONE);
    SetRenderState(D3DRS_DESTBLENDALPHA,D3DBLEND_INVSRCALPHA);
    SetRenderState(D3DRS_BLENDOPALPHA,D3DBLENDOP_ADD);

    と設定すれば良いのですが、カラー側についてはDestのアルファも使うブンレンディングモードの設定が無いためどうしようもありません。これを完全に再現するにはシェーダを駆使するしかないかもしれません(可能ですが非効率になります)。
引用返信 削除キー/
■1431 / inTopicNo.3)  Re[2]: 半透明と半透明のアルファブレンドについて
□投稿者/ 痺れ団子 -(2008/12/17(Wed) 00:19:43)
    2008/12/17(Wed) 00:20:24 編集(投稿者)

    ご返信ありがとうございます。

    正攻法では無理ということで、すっきりしました。
    正攻法ではない、例えば(可能なのかどうか分からないただの妄想ですが)1ピクセルずつDestとSrcの情報を取得して、自前でブレンド計算したものをブレンドなしで描く等といった、泥臭い方法も難しいという理解でよろしいのでしょうか?

    恥ずかしながらシェーダの事を全く理解しておりませんが、可能であるのなら効率を犠牲にしても実現したいと考えますので、とりあえず勉強して挑戦してみたいと思います。
引用返信 削除キー/
■1432 / inTopicNo.4)  Re[3]: 半透明と半透明のアルファブレンドについて
□投稿者/ IKD -(2008/12/17(Wed) 12:05:52)
http://marupeke296.com
     正攻法は多分無理そうな気配でして、痺れ団子さんが仰るようにシェーダにてDestの情報を取得してそれを描き込むという方法が唯一かなと感じております。
     
     シェーダは簡単に言えば「ピクセルに何の色を塗るか」を自分で完全に定義できる仕組みです。本来DirectXが裏でやってくれている仕事をうばって自前専用に書けるので、誇大に言えば何でもできます。
     
     本件の場合、Destとなる描画中の絵(サーフェイス)とSrcとなる情報(ポリゴンやテクスチャの情報)をシェーダ内に読み込み、双方から点の情報を取得してPhotoShopの合成式に代入し、その結果を出力先のサーフェイスに穿ちます。この作業自体はとても単純で簡単です。
     
     問題はDestとなる描画中のサーフェイスを出力先のサーフェイスに充てる事ができないというシェーダの仕様です(同じサーフェイスをシェーダの入出力に使ってはいけない)。これにより、「参照用」と「出力用」の2枚の絵を常に描き続けなければなりません。
     
     シェーダを書いて実行した事が無い状態ですと厳しいかもしれませんが、それを実現するシェーダの手順を模式図にしてみました:
     
    http://marupeke296.com/DLFiles/Question/QUESTION_1423_01.gif

    理屈上はこれで実現可能ですが、実際は色々と紛れも生じてくるかなと想像しています。


     いきなりこれを実現するにも何をして良いか全くわからない状態だと思いますので、まずはシェーダの仕組みを理解し、簡単な描画を一通りできるようになってから挑戦してみると良いかもしれません。
     
     
     シェーダを使わずに描画中のサーフェイスをロックし(IDirect3DSurface9::LockRectメソッド)ピクセル情報を直接取り出して合成する道もあるにはあります。シェーダ利用時よりも幾分簡単ですが、GPUではなくてCPUの力を使うため速度が相当に遅くなると予想されます。ロックはバックバッファに対しては不可なので、最後にバックバッファにコピーが必要になる手間も生じます。
     
     いずれの方法も面倒な部分が沢山出てきまして泥臭さはぬぐえませんが、実現は可能であるはずなので、よろしければご検討下さい。もしもっとうまい方法が見つかりましたら是非教えて下さい。
引用返信 削除キー/
■1434 / inTopicNo.5)  Re[4]: 半透明と半透明のアルファブレンドについて
□投稿者/ 痺れ団子 -(2008/12/18(Thu) 00:32:45)
    2008/12/18(Thu) 00:33:07 編集(投稿者)

    重ね重ね、ご丁寧にありがとうございます。

    こちらのサイトにシェーダの記事がある事に今になって気付く、というとんだ失礼をいたしまして、手間をおかけして申し訳ありませんでした。
    おかげさまで、シェーダの概念とそれを用いた理論的な部分まで、すっきり飲み込めました。
    その上で、今回のケースでは、シェーダを用いるのがDirectX的には正攻法に近いのかなと思います。
    時間はかかると思いますが、記事を熟読させていただいて、是非とも実装に向けて挑戦してみたいと思います。

    何か面白い事が分かれば、また報告させていただきたいと思います。
    本当にありがとうございました。

済!
引用返信 削除キー/



トピック内ページ移動 / << 0 >>

このトピックに書きこむ

書き込み不可

Pass/

HOME HELP 新規作成 新着記事 トピック侮ヲ 検索 過去ログ

- Child Tree -