DirectXによるポリゴンの表示

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Libra

DirectXによるポリゴンの表示

#1

投稿記事 by Libra » 15年前

現在、DirectX9.0で画像を表示するプログラムを作成しています。
今、ポリゴンの表示を使って図形を描画(テクスチャを貼らない)
しようとしているのですが、
ウィンドウモードからフルスクリーンに切り替え以降、
ウィンドウを戻してもポリゴンが表示されなくなってしまいます。
しかし、テクスチャを貼って表示するポリゴンは表示されます。

・SetTexture( 0 , NULL )を設定
・DrawPrimitive( D3DPT_TRIANGLESTRIP , 0 , 2 ) で表示

現在分からない部分
// 頂点バッファの作成
if( FAILED( lpD3DDev->CreateVertexBuffer( sizeof( PolygonVertex ) * 4 , D3DUSAGE_WRITEONLY , FVF_VERTEX2D , D3DPOOL_MANAGED , &pVertex , NULL ) ) )
{
    return FAILURE ;
}
IDirect3DVertexBuffer9* でバッファを作成して、描画をしています。

・頂点バッファの作成は、構造体が使うポリゴンのサイズが違うごとに行うのか?
今現在、4角形を表示するため、4つの頂点のポリゴンのバッファを作成しているが、
ラインを引くときは、頂点数2になるので、別にバッファが必要なのか?

ラインは描画モードを切り替えても表示されるが、
ウィンドウモードの時の表示される色が薄い感じがする。


開発環境
VC2008EE
C++
DirectX 9.0

添付したソースの実行時の緑色の四角が表示したいものです。

御津凪

Re:DirectXによるポリゴンの表示

#2

投稿記事 by 御津凪 » 15年前

テクスチャを張らないポリゴンを描画する場合、
FVF に指定するフラグには D3DFVF_TEX1 は指定しないようにする必要があります。

これが指定されていると、描画時にテクスチャを SetTexture 関数でセットしていない(あるいは NULL をセットしている)場合、
ポリゴンも表示されなくなるのが普通です。
(1x1のテクスチャをセットするという手もありますが)

Libra

Re:DirectXによるポリゴンの表示

#3

投稿記事 by Libra » 15年前

自分で気づいた点に変更を加えましたが、改善しませんでした・・・。
変更を加えたソースを添付します。

変更点
・ポリゴンを貼らない描画をする時の、頂点座標の構造体を別にした。(u,vの値無し構造体)
・SetTextureは呼ばれないようにデバッグ
・FVFに指定するフラグを(D3DFVF_XYZRHW | D3DFVF_DIFFUSE)にした。

実行結果
描画モードを変更すると、テクスチャ無しのポリゴンが表示されない。
起動時フルスクリーンでも、描画モード変更で描画されなくなる。
テクスチャ無しのポリゴン描画はDrawBox、DrawLineメソッドで行っています。


http://marupeke296.com/DXGSmp_No2_2DPoly.html
ここと同じになるように、やってみたのですが、
描画モードを変更すると上手くいきませんでした。
描画モードを変更しても、線ポリゴンは表示されます。
線と三角形ポリゴンの結果の違いはどこで出ているのでしょうか・・・。

御津凪

Re:DirectXによるポリゴンの表示

#4

投稿記事 by 御津凪 » 15年前

こちらでも表示されなくなる状況を確認しました。

まず、正しくデバイスリセットがなされていないようです。
TestCooperativeLevel 関数をマイフレーム必ず呼び出し、その戻り値をチェックしてください。
それ以外の関数では、デバイスロスト状態でも正しい値を返さない(正しく動作しているようにふるまう)ためです。

次に、リセットしたら、レンダリングステートなど再設定をしておくことを推薦します。
いくつかのステートや行列設定もリセットされますので。

Libra

Re:DirectXによるポリゴンの表示

#5

投稿記事 by Libra » 15年前

回答ありがとうございます。m(_ _)m

TestCooperativeLevel関数を使う→値はS_OK
レンダリングステートの設定をメソッドにまとめ、
リセットしたところに処理を挿入したところ、表示されました。
原因は、リセットのあとのレンダリングステートの再設定だったようです。


あとこれとは別に質問があります。



質問1:ポリゴンで円を描くとき、頂点はどのように取ったら良いのでしょうか?

中心と半径を決めて、1個ずつ点の座標を取り、ラインリストで表示
という方法を思いついたのですが、
DirectXのポリゴンで円を描く(または、ポリゴン座標を楽に求める)
関数などは用意されてないのでしょうか?


質問2:頂点バッファを利用して描画を行っているのですが、
引数で指定したバイトサイズ以下の時であれば、描画を一括で行えると思うので、
指定するバイトサイズを大きめに確保するのは良いのでしょうか?

質問1にも関わるのですが、ポリゴンの頂点100個取った円を描画する時に
あらかじめ頂点バッファのサイズを取っておけば
一気に描画出来ると考えました。
この方法は実際にやって良いのでしょうか?


質問3:頂点バッファに用いるLPDIRECT3DDEVICE9

バッファを作成する際、引数でパラメーターを設定しますが、これは
パラメーター毎に変数を用意するべきなのでしょうか?
試しに毎ループこのメソッドを呼び出したところ、
メモリ使用量がどんどん膨れ上がっていきました。


色々検索をかけたりしたのですが、
これが解説されているものが見つかりませんでした。
これらに関するヒントや参考ページ等でも良いので、
教えていただけないでしょうか。お願いします。

御津凪

Re:DirectXによるポリゴンの表示

#6

投稿記事 by 御津凪 » 15年前

> 質問1

ポリゴンで完全な円を表現するのは非効率です。
点ごとに頂点を指定すると、膨大な個数になりやすく、重くなりやすいです。
正多角形の形でポリゴンを構成すれば円に見せることができます。

以下は正多角形のポリゴン位置を構成する関数のサンプルです。
/*!
 * @brief 正多角形ポリゴンを構成する関数。
 * @param outVtx     [out] 構成する頂点配列。最低 inCount + 1 の個数が必要。
 * @param inCount    [in]  構成する角数。
 * @param inHalfSize [in]  半径。
 */
void GenerateCirclePolygon( Vertex* outVtx, UINT inCount, float inHalfSize ){
    outVtx->x = outVtx->y = 0.0f;
    ++outVtx;
    for(UINT i = 0;i < inCount;++i){
        float rad = D3DX_PI * 2.0f * i / inCount;
        outVtx->x = cosf(rad) * inHalfSize;
        outVtx->y = sinf(rad) * inHalfSize;
        ++outVtx;
    }
}
これは、最初の点を原点に置き、そのあとに角数分の点を円に沿って配置しています。
このように構成したポリゴンは D3DPT_TRIANGLEFAN を指定して描画することで正しく表示できます。
これを 3D に応用すれば正多角錐を構成することもできます。

> 質問2

DrawPrimitive 関数の第二引数には、描画に使う頂点データのオフセットを指定できます。
これを利用すれば、頂点バッファに複数のポリゴンデータを持たせ、個別に描画させることができます。
ただし、一括して(一回の呼び出しで)描画する場合は第一引数で指定したプリミティブ構成によっては
形が崩れますので注意してください。

なお、インデックスバッファも併用すれば、比較的楽に一括描画はできるかと思います。

> 質問3

メモリ使用量が膨れ上がっていくのはきちんと解放されていないせいです。

DirectX で作成された全てのデータは、使用が済んだら Release() を呼び出して解放しなければならない決まりがあります。
これは、各データには参照カウントが存在し、参照カウントが 0 になると解放される仕組みになっているからです。

そのため、複数の場所で同じデータを扱う場合は、 AddRef() を呼び出して参照カウントを増やしておく必要もあります。

なお、DirectX 関数群でセットする場合は AddRef() は呼び出す必要はありません。
また、DirectX 関数群でデータを取得する場合は、使用が済んだらRelease() を呼び出して解放する必要があります。
(これらの正確な情報は MSDN ライブラリや SDK リファレンスに載っています)

頂点バッファは、当然のことながら頂点データを格納しているだけのものです。
なので、1頂点を構成する情報が変われば、作成しなおす必要がありますし、
余分な頂点データが混じっていても、DrawPrimitive 関数などで必要な部分だけ描画することもできます。


あと、これらとは関係ないですが、下記のページの文章を一読しておくといいと思います。
リソースの管理 (Direct3D 9)
http://msdn.microsoft.com/ja-jp/library ... 85%29.aspx

専門用語も混じっていますが、その中で「リソース管理は頻繁に変更されるリソースには推奨されない」旨の
説明も含まれてます。

Libra

Re:DirectXによるポリゴンの表示

#7

投稿記事 by Libra » 15年前

> 質問1
説明が不足してました。
御津凪さんに示していただいた実装方法と、
自分の考えていた方法と同じでした。
->(円を描くメソッド) ってのは無いようですね。
パラメーターが D3DPT_TRIANGLEFAN であれば円の中の塗りつぶし、
D3DPT_LINESTRIPであれば、円の中を塗りつぶさないといった形ですね。
1個ずつ点の座標を取り~と書かずに、説明に多角形と書けば良かったですね(汗)

>質問2
>>DrawPrimitive 関数の第二引数には、描画に使う頂点データのオフセットを指定できます。
>>これを利用すれば、頂点バッファに複数のポリゴンデータを持たせ、個別に描画させることができます。
>>ただし、一括して(一回の呼び出しで)描画する場合は第一引数で指定したプリミティブ構成によっては
>>形が崩れますので注意してください。


四角形を表示する時に、
三角形ポリゴンを2つバッファに持たせたあと、
->DrawPrimitive( D3DPT_TRIANGLESTRIP , 0 , 1 ) ;
->DrawPrimitive( D3DPT_TRIANGLESTRIP , 1 , 1 ) ;
といった感じにやるということでしょうか?
(違う気がしますが・・・・)

>>インデックスバッファ
DXライブラリで使用した事があります。
四角形表示するのにも、頂点4つで済むのが楽でした。
頂点数が増えると必要になりそうです・・・。


> 質問3
>>あと、これらとは関係ないですが、下記のページの文章を一読しておくといいと思います。
>>リソースの管理 (Direct3D 9)
>>http://msdn.microsoft.com/ja-jp/library ... 85%29.aspx

>>専門用語も混じっていますが、その中で「リソース管理は頻繁に変更されるリソースには推奨されない」旨の
>>説明も含まれてます。

ということは、パラメーター毎 ( FVFと構造体サイズ (それ以外は同じパラメーター) )
で頂点バッファをある程度の大きさで作成しておき、使うという形でいいのでしょうか?
また、作成したバッファより大きなサイズの頂点データを
->Lock
した場合は、S_OK以外が返るという感じで解釈しました。

バッファを使う度に、作成→使用→開放とやるのは、
恐らくリソースの管理的に良くないとされるのですね?

御津凪

Re:DirectXによるポリゴンの表示

#8

投稿記事 by 御津凪 » 15年前

> 四角形を表示する時に、
> 三角形ポリゴンを2つバッファに持たせたあと、
> ->DrawPrimitive( D3DPT_TRIANGLESTRIP , 0 , 1 ) ;
> ->DrawPrimitive( D3DPT_TRIANGLESTRIP , 1 , 1 ) ;
> といった感じにやるということでしょうか?

そんな感じです。
ただ、この場合はそもそも
->DrawPrimitive( D3DPT_TRIANGLESTRIP , 0 , 2 ) ;
でいいので分ける利点はありませんね。


基本、頂点バッファは一つの物体に一つ持つようにするのが普通です。(3Dモデルとか複雑な物体)
ですが、単純なもの(三角形や四角形など)の場合は、グループ分けするように一つの頂点バッファに纏めて
一括描画(非表示部分はゼロ初期化するなどして対処)でやると効率的に良いです。

> バッファを使う度に、作成→使用→開放とやるのは、
> 恐らくリソースの管理的に良くないとされるのですね?

上記の URL では、 D3DPOOL_MANAGED で作成したリソースを頻繁にロックし、書き換えるという動作は
処理速度の低下につながる恐れがある、というような文面があります。
私はそれを伝えるためにも URL を張っておきました。


「作成」は、初期化時やとある場面から必要になった時に行い、
「開放」は、それ以降使用されなくなった場合に行うのがベストです。
毎フレーム作成や開放を行っていては非効率になります。


参考になるかどうかわかりませんが、
私のサイトで公開しているゲームライブラリのサンプルゲームがあり、
それをオープンソースとして公開しています。
その中に DrawPrimitive 周り(正確には DrawPrimitiveUP と DrawIndexedPrimitiveUP )を使用している
コードがありますので、気になったら見てみてください。
ただし、読みやすいとは言えないのでその点ご了承を。

なお、将来 DirectX 10 以降を使用して構築する場合は注意してください。
別物と言っていいほど構造が違いますので。

(そのうち DX11 講座みたいなの書いてみようかな)

Libra

Re:DirectXによるポリゴンの表示

#9

投稿記事 by Libra » 15年前

>>上記の URL では、 D3DPOOL_MANAGED で作成したリソースを頻繁にロックし、書き換えるという動作は
>>処理速度の低下につながる恐れがある、というような文面があります。
>>私はそれを伝えるためにも URL を張っておきました。

D3DPOOL_MANAGED を使うと、速度低下の恐れが有りますが、
それ以上に ->Reset メソッドをした時のデバイスロストの処理関係を
DirectXに色々処理を任せることができるので、
(DirectX入門の書く側としては)こっちの方、D3DPOOL_MANAGEDを取ることにします。



>>また、作成したバッファより大きなサイズの頂点データを
>>->Lock
>>した場合は、S_OK以外が返るという感じで解釈しました。

試しに、作成したバッファ(構造体8個分)より大きいバッファをロック(構造体0xffff個分)
してみたのですが、S_OKが返りました。
作成したバッファより大きいサイズが指定された場合は、
新たに、サイズのバッファが再作成されるのでしょうか(^^;


>>参考になるかどうかわかりませんが、
>>私のサイトで公開しているゲームライブラリのサンプルゲームがあり、
>>それをオープンソースとして公開しています。
>>その中に DrawPrimitive 周り(正確には DrawPrimitiveUP と DrawIndexedPrimitiveUP )を使用している
>>コードがありますので、気になったら見てみてください。
>>ただし、読みやすいとは言えないのでその点ご了承を。

>>なお、将来 DirectX 10 以降を使用して構築する場合は注意してください。
>>別物と言っていいほど構造が違いますので。

ソースのところまでたどり着きましたが、ソース量が多いので
ゆっくり探してみることにします。
あと、7Zip(?)初めて解凍しました。
サンプルゲームは以前やりましたが、NORMALクリア出来ませんでした。
本家ならHARD行けるんですが・・・。


現在、円と楕円の描画が完成したところです。
少しずつですが、描画出来る図形の種類が増えてくと
嬉しくなってきますね。
おかげでDxlibにのリファレンスには記載されてない機能、
DrawExtendGraphのX、Y軸別倍率指定回転描画や、
図形ポリゴンの角度指定描画など実装出来ました。

現在出来たところまでのソース添付します。


御津凪さん、的確なアドバイスありがとうございました!

御津凪

Re:DirectXによるポリゴンの表示

#10

投稿記事 by 御津凪 » 15年前

> ソースのところまでたどり着きましたが、ソース量が多いので
> ゆっくり探してみることにします。

VC++ にはフォルダ内(GREP)検索(Ctrl+Shift+F)ができますので、それを使って関数名を調べると見つけやすいですよ。

> あと、7Zip(?)初めて解凍しました。

7-Zip は高圧縮率、高速解凍が可能な圧縮形式 LZMA を扱う圧縮・解凍ツールです。
LZMA SDK は自由に使用できるので(zlibより緩いライセンス)、ライブラリのアーカイブ機能に使わせてもらってます。

> サンプルゲームは以前やりましたが、NORMALクリア出来ませんでした。
> 本家ならHARD行けるんですが・・・。

難しいのはすみませんが、現時点で仕様です。
あっさりクリアできてしまうのでは余り面白みが無いですから。
かといって難しすぎるとやる気をそいでしまいますけれども。

> 作成したバッファより大きいサイズが指定された場合は、
> 新たに、サイズのバッファが再作成されるのでしょうか(^^;

実際のサイズより大きな範囲を指定した場合の挙動はリファレンスにも載っていないようです。
しかし、ロックするだけの関数なので、自動で領域を拡張するようなことは無いと思います。
試しに確保より大きなサイズをロックし、その領域に書き込んでみてください。
実行時、アクセス違反のエラーが出たのなら、領域は拡張されておらず、
ロックされた領域は実際のサイズに丸められていることを表します。

Libra

Re:DirectXによるポリゴンの表示

#11

投稿記事 by Libra » 15年前

実際のサイズより大きな範囲を指定し、
ロックしたあと、その領域に適当な数値を書き込んでみたところ、
(作成サイズ構造体4つ分、ロック書き込みサイズ構造体8つ分)
起動中はS_OKのみ返っていましたが、
終了時、RELEASEを行う際に、メモリのアクセス違反が起こりました。
なので、大きな範囲を指定した場合は、
メモリが範囲外を指していることになっているようです。(+起動中範囲外を指していることが検出されない)

あと、描画部分のソースに大きく改変を加え、
バッファをLockして描画しているところを全てPrimitiveUPで描画するようにしたところ、
ピクセルの表示で、処理落ちの起こる回数が
Lock時0xfff個だったのがLock未使用時0x8fffまで増えました。
頻繁にLockするとかなりの速度低下が引き起こされていたようです。

LPDIRECT3DVERTEXBUFFER9のバッファ用変数用意したのに、使わなくなってしまいました(^^;

御津凪

Re:DirectXによるポリゴンの表示

#12

投稿記事 by 御津凪 » 15年前

> なので、大きな範囲を指定した場合は、
> メモリが範囲外を指していることになっているようです。

ということは DirectX 側ではロック範囲を正確にはチェックしていないということになりますね。


> あと、描画部分のソースに大きく改変を加え、
> バッファをLockして描画しているところを全てPrimitiveUPで描画するようにしたところ、
> ピクセルの表示で、処理落ちの起こる回数が
> Lock時0xfff個だったのがLock未使用時0x8fffまで増えました。
> 頻繁にLockするとかなりの速度低下が引き起こされていたようです。

それだけ Lock の回数には気をつけないといけないわけです。
それに、 D3DPOOL によっても大きく差が出ます。
D3DPOOL_MANAGED を指定していたことにも影響があると思います。
多分 D3DPOOL_DEFAULT と D3DUSAGE_DYNAMIC で作成した場合のほうが D3DPOOL_MANAGED より速いはずです。

閉鎖

“C言語何でも質問掲示板” へ戻る