シューティングという事で見てましたが背景とキャラクターを合成するのにアルファブレンドは2Dにおいて最高クラスの機能だと思ってます。
それほど重くもなく、手軽に綺麗な見た目が出せる。
そして、昨今のビデオカードなら大体対応してると思うのですがどう思いますか?
あと、DirectXの描画システムを作ろうと思ってやって居ますが何か参考になるようなことは無いですかね?
以下に箇条書きで大まかに書くとこういった感じです。
1.D3Dオブジェクトの作成。
2.d3dppを投げてデバイスの作成。
3.バックバッファのクリア
4.pDevice->BeginScene();
5.DrawPrimitiveとかで描画
6.pDevice->EndScene();
7.pDevice->Present();
ここで分かりにくいのは4,6,7。
5で描画指示してるのに、何をやっているのですかね?
7.はダブルバッファリングなんで、フリップでもしてるんでしょう。
アルファブレンドについて
Re:アルファブレンドについて
4~7は、Win32API での WM_PAINT に当たると思います。
ただ、DirectXでは、ダブルバッファリングを行うため、バックバッファに描画するのために、
4、6ではそのバックバッファを固定するためだと思います(推測)。
追加で言えば7は垂直同期をしてテアリング(描画の境目が見える現象)が起こるのを防いでくれます。
もちろん2で(垂直同期)しないようにも出来ますけどね。
> 何か参考になるようなことは無いですかね?
アドバイスするとすれば、各ユーザでリフレッシュレートが違うため、
安定した速度を維持できるような処理が必要です。
たとえば、60Hzと120Hzでは2倍の差があります。
そのまま垂直同期を待つ状態だと、120Hzでは2倍の速度でゲームが進んでしまうので注意してください。
ただ、DirectXでは、ダブルバッファリングを行うため、バックバッファに描画するのために、
4、6ではそのバックバッファを固定するためだと思います(推測)。
追加で言えば7は垂直同期をしてテアリング(描画の境目が見える現象)が起こるのを防いでくれます。
もちろん2で(垂直同期)しないようにも出来ますけどね。
> 何か参考になるようなことは無いですかね?
アドバイスするとすれば、各ユーザでリフレッシュレートが違うため、
安定した速度を維持できるような処理が必要です。
たとえば、60Hzと120Hzでは2倍の差があります。
そのまま垂直同期を待つ状態だと、120Hzでは2倍の速度でゲームが進んでしまうので注意してください。
Re:アルファブレンドについて
ありがとうございます。
やっぱ内部で何やってるかが知りたいわけで、聞いてみないとこの辺の情報少ないなぁ。
Beginでエントリー開始して、5.で描画エントリ、Endで描画開始だろうか。
そうするとPresentは描画終了まで待つはずなので、Endの後はCPU処理した方がよさげ?
SetRenderTargetとかで切り替えても平気なんですが、順番と対象は完全に保持されてるのかな。
そんなわけで、効率を考えるなら、
バッファのクリア→Begin→描画→End→更新処理など→Presentがいい気がします。
実際計測したわけじゃないのでなんとも言えないですが。
シェーダーのように描画結果を必要とするものはBegin~End何度も呼ばないといけないかもしれません。
やっぱ内部で何やってるかが知りたいわけで、聞いてみないとこの辺の情報少ないなぁ。
Beginでエントリー開始して、5.で描画エントリ、Endで描画開始だろうか。
そうするとPresentは描画終了まで待つはずなので、Endの後はCPU処理した方がよさげ?
SetRenderTargetとかで切り替えても平気なんですが、順番と対象は完全に保持されてるのかな。
そんなわけで、効率を考えるなら、
バッファのクリア→Begin→描画→End→更新処理など→Presentがいい気がします。
実際計測したわけじゃないのでなんとも言えないですが。
シェーダーのように描画結果を必要とするものはBegin~End何度も呼ばないといけないかもしれません。
Re:アルファブレンドについて
> バッファのクリア→Begin→描画→End→更新処理など→Presentがいい気がします。
シェーダーは使ったことが無いのでそこらへんの効率については分かりませんが、
私の方では、
更新処理など→バッファのクリア→Begin→描画→End→Present
としています。
このとき、更新処理とそれ以外(描画周り)の部分を分けて処理すると、
すっきりとしたコードがかけると思います。
(基礎を構築するのが大変ではありますが)
それと、以下のようにすると、バックバッファではなく、テクスチャに描画することも出来ますよ。
Begin
現在のバックバッファを取得&描画するテクスチャに置き換え
描画
バックバッファを戻す
通常描画
End
シェーダーは使ったことが無いのでそこらへんの効率については分かりませんが、
私の方では、
更新処理など→バッファのクリア→Begin→描画→End→Present
としています。
このとき、更新処理とそれ以外(描画周り)の部分を分けて処理すると、
すっきりとしたコードがかけると思います。
(基礎を構築するのが大変ではありますが)
それと、以下のようにすると、バックバッファではなく、テクスチャに描画することも出来ますよ。
Begin
現在のバックバッファを取得&描画するテクスチャに置き換え
描画
バックバッファを戻す
通常描画
End
Re:アルファブレンドについて
アレコレ試行錯誤した結果プリミティブを増やしてみました。
とりあえず実験した限りでは、今のPC(開発用/かなり高スペック)だと11000個程度まで60fps。
旧PC(Pen4 2.26GHzあたり、グラボもそれなり)だと、3000個ぐらいといった感じ。
ちなみに旧ライブラリが今のPCにおいて、2500個ぐらいで処理落ちを始めます。
一括描画が出来る環境に限定すれば、4倍以上速くなりました。
一括描画出来ないと、きっと2500個程度かそれより劣るでしょう。
ただ、大量に描画するパーティクル等は大抵同じテクスチャになってるはずです。
本格的に弾幕とかで1万発とか出すのは、頂点シェーダーとか使ってるんだろうなぁ。
シェーダー使えば座標変換のためにわざわざバッファをロックしなくても良さそうだし。
とはいえ、市場のグラボが安定してシェーダー対応するまでは中々使いづらいので
そして、一括描画全く使わないでやったら、500個ちょいで処理落ちを始めました。
これじゃどうしようもないので、初期化時にフラグで一括描画するかどうかを選ぶように。
一括描画しない場合はDrawPrimitiveUpで描画を行います。
頂点バッファを何回もロックするのが重いわけで、Up系なら問題なく描画できます。
むしろ、2Dは全部Up系でいいかも?
そこまで極端な差がないし、一括描画自体は使えるので
シンプルな構造を目指すならそういう切捨てはありなのかも。
でもシェーダーとかはだめなのかな?。
頂点バッファを使うかどうかのフラグにした方が正しい気がしてきた。
結論:
頂点バッファは3Dで使うのが効果的であり、
その場合は行列をデバイス経由で渡してやるのが高速。
2D程度はUp系列の関数で大差ない。
つうわけでとりあえず解決にはなりました。
とりあえず実験した限りでは、今のPC(開発用/かなり高スペック)だと11000個程度まで60fps。
旧PC(Pen4 2.26GHzあたり、グラボもそれなり)だと、3000個ぐらいといった感じ。
ちなみに旧ライブラリが今のPCにおいて、2500個ぐらいで処理落ちを始めます。
一括描画が出来る環境に限定すれば、4倍以上速くなりました。
一括描画出来ないと、きっと2500個程度かそれより劣るでしょう。
ただ、大量に描画するパーティクル等は大抵同じテクスチャになってるはずです。
本格的に弾幕とかで1万発とか出すのは、頂点シェーダーとか使ってるんだろうなぁ。
シェーダー使えば座標変換のためにわざわざバッファをロックしなくても良さそうだし。
とはいえ、市場のグラボが安定してシェーダー対応するまでは中々使いづらいので
そして、一括描画全く使わないでやったら、500個ちょいで処理落ちを始めました。
これじゃどうしようもないので、初期化時にフラグで一括描画するかどうかを選ぶように。
一括描画しない場合はDrawPrimitiveUpで描画を行います。
頂点バッファを何回もロックするのが重いわけで、Up系なら問題なく描画できます。
むしろ、2Dは全部Up系でいいかも?
そこまで極端な差がないし、一括描画自体は使えるので
シンプルな構造を目指すならそういう切捨てはありなのかも。
でもシェーダーとかはだめなのかな?。
頂点バッファを使うかどうかのフラグにした方が正しい気がしてきた。
結論:
頂点バッファは3Dで使うのが効果的であり、
その場合は行列をデバイス経由で渡してやるのが高速。
2D程度はUp系列の関数で大差ない。
つうわけでとりあえず解決にはなりました。
Re:アルファブレンドについて
>5.で描画エントリ、Endで描画開始だろうか
ひょっとすると環境毎に異なるかもしれませんが、イメージとしては
5は描画パケットを GPUに投げて描画(GPUが処理中ならキューへ)じゃないですかね、多分。
>効率を考えるなら、
>バッファのクリア→Begin→描画→End→更新処理など→Presentがいい気がします。
それをすると、キーの判定から実際に画面に描画されるまでのレーテンシーが
1フレーム遅れませんか?
単純に考えると CPUが1つしかないのであれば御津凪さんの方法がいいかと思います。
2つ以上ある環境なら、更新処理と描画を別々のスレッドで行うようにすると
[データを更新->次のフレームで描画しつつ、更新を同時に]
という風に描画が1フレーム遅れますが、更新・描画をそれぞれを1フレーム
丸ごと(若干語弊がありますが)かけて処理できるようになりますよ。
システムの構築がちょっと大変ですけどね。
ひょっとすると環境毎に異なるかもしれませんが、イメージとしては
5は描画パケットを GPUに投げて描画(GPUが処理中ならキューへ)じゃないですかね、多分。
>効率を考えるなら、
>バッファのクリア→Begin→描画→End→更新処理など→Presentがいい気がします。
それをすると、キーの判定から実際に画面に描画されるまでのレーテンシーが
1フレーム遅れませんか?
単純に考えると CPUが1つしかないのであれば御津凪さんの方法がいいかと思います。
2つ以上ある環境なら、更新処理と描画を別々のスレッドで行うようにすると
[データを更新->次のフレームで描画しつつ、更新を同時に]
という風に描画が1フレーム遅れますが、更新・描画をそれぞれを1フレーム
丸ごと(若干語弊がありますが)かけて処理できるようになりますよ。
システムの構築がちょっと大変ですけどね。
Re:アルファブレンドについて
まぁいずれにせよアドバイスもさることながら満足できる方向に進めたのでよしとします。
後先日参加したCEDEC2008なんかも理解半分といったところですがいい参考にはなったりしたんでw
某ねずみでお馴染みのゲーム会社で仕事としてプログラムそしてこうした趣味でゲームプログラムなんである意味息抜きにも近いんですが。
とにかくありがとうございました。
後先日参加したCEDEC2008なんかも理解半分といったところですがいい参考にはなったりしたんでw
某ねずみでお馴染みのゲーム会社で仕事としてプログラムそしてこうした趣味でゲームプログラムなんである意味息抜きにも近いんですが。
とにかくありがとうございました。