トップページ > 記事閲覧
DrawPolygonIndexed3DToShaderni
名前:ffm8 日時: 2013/05/25 23:39

いくつか質問があります。長文になってしまい申し訳ありません。お時間のあるときに1つずつでも教えていただければ幸いです。 0.前提として、私は大量のパーティクルの描画をできるだけ自由に行うことが大きな目標としており、 最近まではDrawPolygonIndexed3Dで描画を行なっており、リリースビルドしたもので大体6000〜7000枚程度までの満足の行く操作を含めたビルボードを60fpsで描画出来ていました。 しかし行列演算が多く、シェーダを書いてGPUで演算すれば少なくとも10万枚程度は描画出来ると考え、開発を進めてきました。 PCの簡単なスペックはCPU:2500K GPU:7750 メモリ:12GB OS:win7_64bitです。 質問に関わるコードを貼っておきます。下の質問からお読みになって下さい。 for( i = 0 ; i < MAX_PARTICLE_NUMBER ; i ++ ) { //指向軸ベクトルの取得 Direct =VNorm( Particle[ i ].V); //Particle[ i ].Vはそのパーティクルの速度ベクトルです // 4頂点分のデータをセット Vertex[ 4*i+0 ].pos = VGet(Particle[ i ].size_pos_1_x,Particle[ i ].size_pos_1_y,0); //※1 後述します Vertex[ 4*i+0 ].norm = VGet(0,0,-1); Vertex[ 4*i+0 ].dif = GetColorU8(Col_r_Now,Col_g_Now,Col_b_Now,Col_a_Now) ; Vertex[ 4*i+0 ].spc = GetColorU8( 0, 0, 0, 0 ) ; Vertex[ 4*i+0 ].u = 0.0f ; Vertex[ 4*i+0 ].v = 0.0f ; Vertex[ 4*i+0 ].su = 0.0f ; Vertex[ 4*i+0 ].sv = 0.0f ; Vertex[ 4*i+1 ].pos = VGet(Particle[ i ].size_pos_2_x,Particle[ i ].size_pos_2_y,0); Vertex[ 4*i+1 ].norm = VGet(0,0,-1)); Vertex[ 4*i+1 ].dif = GetColorU8(Col_r_Now,Col_g_Now,Col_b_Now,Col_a_Now) ; Vertex[ 4*i+1 ].spc = GetColorU8( 0, 0, 0, 0 ) ; Vertex[ 4*i+1 ].u = 0.0f ; Vertex[ 4*i+1 ].v = 1.0f ; Vertex[ 4*i+1 ].su = 0.0f ; Vertex[ 4*i+1 ].sv = 0.0f ; Vertex[ 4*i+2 ].pos = VGet(Particle[ i ].size_pos_3_x,Particle[ i ].size_pos_3_y,0); Vertex[ 4*i+2 ].norm = VGet(0,0,-1); Vertex[ 4*i+2 ].dif = GetColorU8(Col_r_Now,Col_g_Now,Col_b_Now,Col_a_Now) ; Vertex[ 4*i+2 ].spc = GetColorU8( 0, 0, 0, 0 ) ; Vertex[ 4*i+2 ].u = 1.0f ; Vertex[ 4*i+2 ].v = 0.0f ; Vertex[ 4*i+2 ].su = 0.0f ; Vertex[ 4*i+2 ].sv = 0.0f ; Vertex[ 4*i+3 ].pos = VGet(Particle[ i ].size_pos_4_x,Particle[ i ].size_pos_4_y,0); Vertex[ 4*i+3 ].norm = VGet(0,0,-1); Vertex[ 4*i+3 ].dif = GetColorU8(Col_r_Now,Col_g_Now,Col_b_Now,Col_a_Now) ; Vertex[ 4*i+3 ].spc = GetColorU8( 0, 0, 0, 0 ) ; Vertex[ 4*i+3 ].u = 1.0f ; Vertex[ 4*i+3 ].v = 1.0f ; Vertex[ 4*i+3 ].su = 0.0f ; Vertex[ 4*i+3 ].sv = 0.0f ; // 2ポリゴン分のインデックスデータをセット Index[ 6*i+0 ] = 4*i+0 ; Index[ 6*i+1 ] = 4*i+1 ; Index[ 6*i+2 ] = 4*i+2 ; Index[ 6*i+3 ] = 4*i+3 ; Index[ 6*i+4 ] = 4*i+2 ; Index[ 6*i+5 ] = 4*i+1 ; // シェーダ定数を設定(レジスタへ渡す) FLOAT4 f4array[ 6 ] ; f4array[ 0 ].x = Direct.x ; f4array[ 0 ].y = Direct.y ; f4array[ 0 ].z = Direct.z ; f4array[ 0 ].w = 0 ; f4array[ 1 ].x = Particle[ i ].L_Axes.x ; //前フレームでの外積軸です。シェーダでローカル軸を求める際に使います。 f4array[ 1 ].y = Particle[ i ].L_Axes.y ; f4array[ 1 ].z = Particle[ i ].L_Axes.z ; f4array[ 1 ].w = 0 ; f4array[ 2 ].x = Particle[ i ].pos.x ; //パーティクルの座標 f4array[ 2 ].y = Particle[ i ].pos.y ; f4array[ 2 ].z = Particle[ i ].pos.z ; f4array[ 2 ].w = 0 ; f4array[ 3 ].x = Particle[ i ].rotX ; //パーティクルのローカル各軸の自転角度 f4array[ 3 ].y = Particle[ i ].rotY ; f4array[ 3 ].z = Particle[ i ].rotZ ; f4array[ 3 ].w = 0 ; f4array[ 4 ].x = sizeX_Now ; //パーティクルの大きさ f4array[ 4 ].y = sizeY_Now ; //時間に応じた展開などのためにこれの上でそのフレームでのサイズを算出しています f4array[ 4 ].z = sizeZ_Now ; //今のところビルボードしか考えていないので事実上Z軸は無意味です f4array[ 4 ].w = 0 ; f4array[ 5 ].x = cam[ sys.Control_No ].Eye.x ; //操作機体のカメラ座標 f4array[ 5 ].y = cam[ sys.Control_No ].Eye.y ; f4array[ 5 ].z = cam[ sys.Control_No ].Eye.z ; f4array[ 5 ].w = 0 ; SetVSConstFArray( 43, f4array, 5 ) ; //※1 size_pos〜はパーティクルの座標からローカル軸に沿って、サイズの何倍移動した点かを決定するための値です //基本的にVertex[0]には(0.5 , 0.5 , 0)、Vertex[1]には(-0.5 , 0.5 , 0)、Vertex[2]には(0.5 , -0.5 , 0)、Vertex[3]には(-0.5 , -0.5 , 0)となっています //そのパーティクルの要望に応じてシェーダを選択 if() { // 使用する頂点シェーダーのセット SetUse VertexShader( Shader.Vsfor_Particle1 ) ; } //そのパーティクルの要望に応じてシェーダを選択 if() { // 使用するピクセルシェーダーをセット SetUsePixelShader( Shader.Psfor_Particle1 ) ; } // 使用するテクスチャを0番にセット SetUseTextureToShader( 0, Particle[ i ].GrHandle ) ; // 2ポリゴンのシェーダ使った描画 DrawPolygonIndexed3DToShader( Vertex, 4*MAX_PARTICLE_NUMBER, Index+6*i, 2 ) ; } //頂点シェーダ //簡単に書きます。 // C++ 側で設定する定数の定義 float4x4 cfViewMatrix : register( c6 ) ; // ワールド座標をビュー座標に変換する行列の転置行列 float4x4 cfProjectionMatrix : register( c2 ) ; // ビュー座標を射影座標に変換する行列の転置行列 float3 cfDirect : register( c43 ); // 指向軸 float3 L_Axes : register( c44 ); // 前フレームでの外積軸 float4 P_pos : register( c45 ); // パーティクルの座標 float4 P_Rot : register( c46 ); // パーティクルのx,y,z軸回転角 float4 P_Size : register( c47 ); // パーティクルのx,y,z軸方向の展開中の今フレームのサイズ。 float4 Cam_pos : register( c48 ); // カメラの座標 //ローカル軸の取得 Local_Axes_Y = 先ほどのDirectベクトルと(0,1,0)ベクトルの外積 Local_Axes_Z = DirectベクトルとLocal_Axes_Yの外積 if(Local_Axes_Yが零ベクトル) {前フレームの外積軸から求めます。それでも零ベクトルのときは(1,0,0)ベクトルとの外積から求めます。} Size_X_tmp = Local_Axes_X *VSInput.Position.x *P_Size.x; Size_Y_tmp = Local_Axes_Y *VSInput.Position.y *P_Size.y; lWorldPosition = Size_X_tmp+ Size_Y_tmp +P_pos; // 頂点座標をビュー空間の座標に変換する lViewPosition = mul( lWorldPosition, cfViewMatrix ) ; // ビュー空間の座標を射影空間の座標に変換する VSOutput.ProjectionPosition = mul( lViewPosition, cfProjectionMatrix ) ; // テクスチャ座標はそのまま代入 VSOutput.TextureCoord0 = VSInput.TextureCoord0; // 頂点カラーはそのまま代入 VSOutput.DiffuseColor = VSInput.DiffuseColor ; // 関数の戻り値がピクセルシェーダーに渡される return VSOutput ; //ピクセルシェーダは頂点シェーダのテスト中なのでとりあえず //出力する色はテクスチャの色と C++ で設定した値とディフューズカラーを乗算したもの を出力しています。 質問 1.ソースコードについて 大まかな流れはパーティクルの座標一点で運動(別ソース)させ、描画の際にのみローカル軸に沿って四点に広げるといった形です。 任意軸回転などの演算が重なっても描画の際のローカル軸のみで済む分、演算量が少ないと思うのでこのような書き方をしていますが、 これをコンパイルして実行してもうまく描画されません。ワールド座標の原点からpos方向に非常に細長いビルボードが描画されます。 さらにVertex[].posを0.5と-0.5以外の数字(1と0や2と1で同じ表現)では描画すらされません。 しかしシェーダの演算をVertex[].posの前に行い、直接Vertex[].posに入れてやると想像通りの結果が描画されます。 また、ローカル軸を無視して lWorldPosition = VSInput.Position *1000 + P_pos としてもきちんと描画されます。(理想通りではないですが) シェーダでの演算の次元はきちんと合うようにしました。正直手詰まりです。おかしなところがあればご指摘お願い致します。 2.シェーダの値の流れについて 上の質問と重なりますが、頂点シェーダのVertex[].posは4頂点の値を1頂点ずつ(VSInputが行列ではなくベクトル型なので)シェーダの処理をし、 最後にIndexと描画ポリゴン数から4頂点を関連付けていると考えているのですが、間違っているでしょうか?(Yes or Noで結構です) シェーダの例を見ているとローカル座標から4頂点共に同じ回転行列などをかけて、ワールド変換、ビュー空間、射影空間と変換しているものばかりなので 上の書き方はすごく奇特に見え、初心者なのでなにか特別な扱いがなされているのではないかと心配です。 3.DrawPolygonIndexed3DToShaderの引数について 以前 ttp://hpcgi2.nifty.com/natupaji/bbs/patio.cgi?mode=view&no=2764 こちらでDrawPolygonIndexed3Dの質問をさせていただいたときから DrawPolygonIndexed3D( Vertex, 4*MAX_PARTICLE_NUMBER, Index+6*i, 2, Particle[ i ].GrHandle, TRUE ) ; としてきていましたが、 毎パーティクルごとに呼ぶなら 描画する三角形ポリゴンの数が2なので 第二引数のint VertexNum:使用する頂点の数 は4にはならないのでしょうか?(Yes or Noで結構です) 4.DrawPolygonIndexed3DToShaderの呼び出し回数について 現在一つのビルボードを描画するたびに呼び出しているので、毎フレーム数千回呼び出していることになりますが、 テクスチャが同じものは一回の呼び出しで一挙に描画するほうがやはり速いでしょうか。また、その差はかなり大きいですか?(それぞれYes or Noで結構です) 5.描画関数の速度について 今まで、DrawBillboard3DやDrawPolygonIndexed3D、DrawPolygonIndexed3DToShaderを使って来ましたが、 どうもDrawBillboard3Dが最も早かった印象です。冒頭に戻りますが、DrawPolygonIndexed3DToShaderを用いて、自分の出来る限り演算を省いたシェーダを書いてみましたが 3000〜4000枚でも画面の大部分を覆うと簡単に20〜30fpsまで落ちてしまい、CPUでDrawPolygonIndexed3Dを用いて描画した方が圧倒的に速かったです。 内部処理がよくわからないので教えていただきたいのですが、適切に扱えたならばDrawPolygonIndexed3DToShaderを用いた方が他の描画関数と同じ処理をしたとき、速いといえるでしょうか? また、シェーダを使っていなかった時でもGPUの使用率が上がることがありましたが、これは内部で何らかの演算に使われているのでしょうか?それともただの動画視聴のようにDXlibとは無関係な部分での負荷でしょうか? (それぞれYes or Noで結構です) 6.レジスタへの値の渡しについて こちらもパーティクルごとにそれぞれの座標などを渡しているので毎フレーム数千回渡していることになりますが、これは非常識でしょうか? とにかくパーティクル関係の演算をGPUに任せることで高速化を、と考えているのですが余計でしょうか。 MMDのMMEではif分の混ざった、行列演算も多いfxファイルのエフェクトが私の環境では50万パーティクルまではほぼ60fpsを保っていたため、(70万程度でGPU100%、処理落ち。CPUは10%以下) 一年近くの間、シェーダを随分当てにして開発を行っていました。 最適化など、様々な問題があると思われますが、それでも5万以上程度のパーティクルは扱ってみたいのです。 こういったことをするにはDXライブラリでは苦しいものがあるでしょうか。 また、あまり調べていませんがGPGPUのCUDAなどを導入することは助けになりそうでしょうか。 それとも私が未熟なだけで、シェーダのテクニックなどを除けばDXライブラリで充分大量のパーティクルを描画することぐらいは出来るでしょうか。 大変長くなり、誠に恐縮ですがお時間のあるときにでも教えていただけたらと思います。よろしくお願いします。
メンテ

Page: 1 | 2 |

Re: DrawPolygonIndexed3DToShaderni ( No.2 )
名前:管理人 日時:2013/05/26 14:56

> 毎パーティクルごとに呼ぶなら 描画する三角形ポリゴンの数が2なので 第二引数のint VertexNum:使用する頂点の数 は4にはならないのでしょうか?(Yes or Noで結構です) Yes > テクスチャが同じものは一回の呼び出しで一挙に描画するほうがやはり速いでしょうか。 Yes > また、その差はかなり大きいですか? Yes > 適切に扱えたならばDrawPolygonIndexed3DToShaderを用いた方が他の描画関数と同じ処理をしたとき、速いといえるでしょうか? Yes > また、シェーダを使っていなかった時でもGPUの使用率が上がることがありましたが、これは内部で何らかの演算に使われているのでしょうか?それともただの動画視聴のようにDXlibとは無関係な部分での負荷でしょうか? GPUはシェーダーの実行以外にも色々描画処理には関わっていますので何も不思議は無いと思います > こちらもパーティクルごとにそれぞれの座標などを渡しているので毎フレーム数千回渡していることになりますが、これは非常識でしょうか? はい GPUへのアクセスをなるべく減らして、CPUの指示無くGPUが稼動する時間が長ければ長いほどGPU使用のメリットが大きくなりますので、 1パーティクル毎にシェーダーの変更やレジスタの値を変更すると、シェーダーを使用する意味は殆ど無いどころか、シェーダーを使用しないほうが良いくらいになります なので、一般的には一つの大きなテクスチャーに複数のパーティクルの画像を敷き詰めて、パーティクル毎に変化するパラメータは 全て頂点データに埋め込んで、一回の DrawPolygonIndexed3DToShader でどれだけ沢山のパーティクルを描画できるかどうかが DrawPolygonIndexed3DToShader などの「頂点データとインデックスデータを渡してポリゴンを描画する関数」による高速化のキモになります DrawBillboard3D では DrawBillboard3D を呼ぶだけではGPUへはまだ描画の指令は飛ばさず情報をストックしておいて、テクスチャの変更や 描画ブレンドモードの変更等、一度の DrawPolygonIndexed3DToShader( の、ような内部の関数 )では処理できない変化が発生したときに ストックしておいたポリゴンの情報を一度に GPU に描画させていますので、1パーティクル毎に DrawPolygonIndexed3DToShader で 描画するより高速になります > こういったことをするにはDXライブラリでは苦しいものがあるでしょうか。 DrawPolygonIndexed3DToShader では頂点データの型が固定なので生で Direct3D を扱う場合よりも不利かもしれませんが、実装は可能だと思います > また、あまり調べていませんがGPGPUのCUDAなどを導入することは助けになりそうでしょうか。 私も詳しくは知りませんが以前CPU処理では絶対に不可能な量のパーティクルをCUDAで処理して描画しているという動画は見たことがあります ただ GeForce でしか CUDA は使用できませんので、Redeon HD 7750 をお使いでしたら使用することはできません > それとも私が未熟なだけで、シェーダのテクニックなどを除けばDXライブラリで充分大量のパーティクルを描画することぐらいは出来るでしょうか。 十分大量というのがどのくらいの数なのか、またどのくらいのスペックのPCを想定するのかにもよりますが、 MMEの10分の1の数で良いということでしたら可能だと思います
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.3 )
名前:ffm8 日時:2013/05/26 16:16

回答ありがとうございます 随分状況が整理され、見通しがたったように思います >> 毎パーティクルごとに呼ぶなら 描画する三角形ポリゴンの数が2なので 第二引数のint VertexNum:使用する頂点の数 は4にはならないのでしょうか?(Yes or Noで結構です) >Yes 質問の仕方が悪かったです申し訳ありません。これはVertexNumが4にはならない、ということでよろしいでしょうか? >なので、一般的には一つの大きなテクスチャーに複数のパーティクルの画像を敷き詰めて、パーティクル毎に変化するパラメータは 全て頂点データに埋め込んで、一回の DrawPolygonIndexed3DToShader でどれだけ沢山のパーティクルを描画できるかどうかが DrawPolygonIndexed3DToShader などの「頂点データとインデックスデータを渡してポリゴンを描画する関数」による高速化のキモになります となると2Dで言うDrawRectGraphのような処理が必要ということでしょうか グラフィックハンドルは出来る限り少数にし、シェーダのテクスチャ座標で描画するエフェクトを指定するといった形になるのでしょうか? 他人様のモデルデータなどを拝見するとテクスチャがまとまった画像が幾つかあるだけである理由がようやくわかりました シェーダ使ってなくてもGPUに処理はさせていたのですね…… グラボ積む前後であまり描画数が変わらなかったのでCPUのみに依存していると思っていました 最悪CUDAのためにグラボの買い替えも検討していたのですが、まだまだDXライブラリ一本で行けそうですね 開発環境の前にまだまだやるべきこと、やれることがあるのがよく分かりました もう少し頑張ってみます。
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.4 )
名前:ffm8 日時:2013/05/26 16:41

連投すみません もう一つお願いします パーティクルの一括描画の際にテクスチャ決定がネックで実装できなかったのは解決出来ましたが、 今のところ4頂点の算出はCPUで行うしかありません 4頂点の算出に行列演算をそれなりに含みますのでGPUで計算したいのですが、 さすがにこれをするにはGPGPUしかないでしょうか?
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.5 )
名前:管理人 日時:2013/05/26 18:29

> 質問の仕方が悪かったです申し訳ありません。これはVertexNumが4にはならない、ということでよろしいでしょうか? すみません私もYes,Noで分かりにくいことに気が付きませんでした、VertexNum は 4 で OK ということです > グラフィックハンドルは出来る限り少数にし、シェーダのテクスチャ座標で描画するエフェクトを指定するといった形になるのでしょうか? はい > 4頂点の算出に行列演算をそれなりに含みますのでGPUで計算したいのですが、 > さすがにこれをするにはGPGPUしかないでしょうか? 4頂点の中のどの頂点なのかの情報( 0〜3 の値など )を頂点データの何かの変数に代入しておいて、 頂点シェーダー内でその値を使用して各頂点毎に処理を分ける必要のある部分をif文で分岐して処理するという手があります if文を多用することになるのでGPUの負担は増しますがCPUで処理するよりは断然高速に処理できると思います ( あとシェーダーコードが長くなるので頂点シェーダーをコンパイルする際はシェーダーモデル3.0を指定する必要があると思います ) そういえば頂点シェーダー内での頂点と行列の乗算ですが、 mul( 頂点, 行列 ) と書く場合と mul( 行列, 頂点 ) と書く場合で計算結果が違いますので、その辺りが問題になっているかもしれません
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.6 )
名前:ffm8(解決) 日時:2013/05/26 22:05

速度の上下関係なども理解が深まり、不安要素の整理も出来たことで ほとんどの疑問も無くなり、見通しにとても希望を持つことが出来ました 分かりにくい文章にお付き合いいただいてありがとうございました これで解決としたいと思います
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.7 )
名前:ffm8 日時:2013/06/02 01:15

一旦終わったのに度々すみません 実装自体は9割出来ましたが最後にもう少しだけ疑問に答えていただけないでしょうか 1.シェーダのセットもレジスタと同じく毎パーティクル変更は良くないでしょうか? シェーダの勉強をしていると、とことんまで最適化され、用途別にマイナーチェンジしたシェーダを多数用意し、処理するべき、とも聞いたのですが 2.また、HLSLのセマンティクスはPOSITION[n]などとなっていますが DXライブラリで渡せるのはn=0のベクトルだけでしょうか? それとデバッグをしているとVertexの中にposの他にspos、tan、binormがあるようですが…… tan、binormはTANGENT[n]、BINORMAL[n]なのでしょうがsposとは何でしょうか? また、それぞれに値を渡すことは出来るでしょうか 別にセマンティクスをサポートしていなくてもパーティクルごとの回転角などを渡せればさらに大きくCPUの負荷を減らすことができますので…… 3.また、今のところVGetを用いて渡しているのですが4次元ベクトルを渡したい場合はGetColorU8を使うことになるのでしょうか(Yes or Noで結構です) 4.DrawPolygonIndexed3DToShaderで一括描画する際、無効なパーティクルの描画をスキップしたいのですが これはPOSITIONが4頂点とも0になるようにして、大きさ0のポリゴンを描画するしかないでしょうか? 5.DrawPolygonIndexed3DToShaderでもSetDrawBlendModeの影響を受けるようですが ピクセルシェーダを使う以上SetDrawBlendModeの操作は余計になると思うのですが DX_BLENDMODE_NOBLENDまたはSetDrawBlendModeを使わなければシェーダ以外の操作は行われないということでよろしいでしょうか?(Yes or Noで結構です) ご指導のおかげ様で、とりあえずテクスチャ、シェーダを固定の環境で、1万パーティクルごとに描画するようにすることで パーティクル数が2万になる辺りまで60fpsを維持できるようになりました ボトルネックはパーティクルの運動の計算のCPU負荷のようです。GPUは30%に満たない程度です ですので2.次第ではまだまだ数を増やせそうです。ただ、4万程度になるとアイドル時でもforループだけで処理落ちが…… for内の最適化が必要になってきそうです
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.8 )
名前:管理人 日時:2013/06/02 18:49

> 1.シェーダのセットもレジスタと同じく毎パーティクル変更は良くないでしょうか? はい、良くないです No.2で申し上げました通り設定の変更でGPUがストップしてしまいますので > シェーダの勉強をしていると、とことんまで最適化され、用途別にマイナーチェンジしたシェーダを多数用意し、処理するべき、とも聞いたのですが 時と場合によりますが、少なくともパーティクル一つ( 2ポリゴン )毎にシェーダを変更するくらいなら 色々なケースに対応できる重いシェーダで一度に沢山のパーティクルを描画したほうが高速です > 2.また、HLSLのセマンティクスはPOSITION[n]などとなっていますが > DXライブラリで渡せるのはn=0のベクトルだけでしょうか? > それとデバッグをしているとVertexの中にposの他にspos、tan、binormがあるようですが…… > tan、binormはTANGENT[n]、BINORMAL[n]なのでしょうがsposとは何でしょうか? spos が POSITION[1] となっています > また、それぞれに値を渡すことは出来るでしょうか メンバ変数( spos, norm, tan, binorm )に値を代入すればシェーダに渡すことができます > 3.また、今のところVGetを用いて渡しているのですが4次元ベクトルを渡したい場合はGetColorU8を使うことになるのでしょうか(Yes or Noで結構です) 4次元ベクトルの値を渡せるのは spos、dif、spc ですが、float型精度で値を渡せるのは spos だけです、 spos は構造体 FLOAT4 型で、メンバ変数が x, y, z, w となっています dif と spc は4次元ベクトルですが各要素8bitしかないので相当精度が荒くても問題ない場合以外では 使用に耐えないと思います > 4.DrawPolygonIndexed3DToShaderで一括描画する際、無効なパーティクルの描画をスキップしたいのですが > これはPOSITIONが4頂点とも0になるようにして、大きさ0のポリゴンを描画するしかないでしょうか? インデックス配列を弄らないのでしたらその方法しかないと思います > 5.DrawPolygonIndexed3DToShaderでもSetDrawBlendModeの影響を受けるようですが > ピクセルシェーダを使う以上SetDrawBlendModeの操作は余計になると思うのですが 一応シェーダでは SetDrawBlendMode の代用はできません( SetDrawBlendMode は描画先バッファのピクセルと 描画元の色との合成設定なので( ピクセルシェーダでは描画元の色の決定にしか関われない ) ) > DX_BLENDMODE_NOBLENDまたはSetDrawBlendModeを使わなければシェーダ以外の操作は行われないということでよろしいでしょうか?(Yes or Noで結構です) ?? DX_BLENDMODE_NOBLENDを使うとはどのような意味でしょうか? 仮に「SetDrawBlendModeを使わなければシェーダ以外の操作は行われないということでよろしいでしょうか?」 こちらの部分だけ読んだ場合ですが、質問が漠然としていてお答えできません、シェーダ以外の操作とは何でしょうか? DrawGraph や SetPSConstF, ScreenFlip など様々な関数が Direct3D を操作しますが・・・
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.9 )
名前:ffm8 日時:2013/06/02 21:12

>時と場合によりますが、少なくともパーティクル一つ( 2ポリゴン )毎にシェーダを変更するくらいなら >色々なケースに対応できる重いシェーダで一度に沢山のパーティクルを描画したほうが高速です では、同じシェーダを使うパーティクルのみまとめて描画と、 シェーダの種類を問わずに一つのif分岐のシェーダでまとめて描画ではどちらが高速か、と考えましたが シェーダの種類とパーティクル数に左右されそうですね ttp://marupeke296.com/SS_No1_FlexbleShaderSystem.html 参考までにこのようなページを見かけたのですが これはピクセルシェーダの話で、一処理に並列して複数のシェーダを使う場合とは違ったのですかね posとnormはfloat3、difとspcは4次元のunsigned charという事ですね tan、binormはfloat3でしょうか?また、sposはどのように4次元ベクトルを渡せばいいのかわかりません Vertex[].spos = なんとすれば良いのでしょうか Vertex[].spos.x =、.y、.z、.wとそれぞれ代入するしか無いでしょうか >?? DX_BLENDMODE_NOBLENDを使うとはどのような意味でしょうか? すみません、ピクセルシェーダで描画先バッファのピクセルとの合成設定に関われると思い込んでいました ですので、ピクセルシェーダを用いた描画とSetDrawBlendModeを両方使うと、同じ操作を二重に行なってしまうと考えていたため、 描画先バッファのピクセルとの合成設定についての、シェーダ以外の操作(SetDrawBlendModeによる合成設定の操作)、という意味でした そのことからピクセルシェーダを使うとSetDrawBlendModeと競合しないようにDX_BLENDMODE_NOBLENDにしておく必要があるのかと勘違いしておりました 大きな勘違いを正していただきありがとうございます Vertexについても理解が深まりました。しかし自分で調べられる範囲も多かったです、お手を煩わせて申し訳ありません これでまた仕様を大きく変えられそうです ありがとうございました
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.10 )
名前:管理人 日時:2013/06/04 23:36

> ttp://marupeke296.com/SS_No1_FlexbleShaderSystem.html > 参考までにこのようなページを見かけたのですが > これはピクセルシェーダの話で、一処理に並列して複数のシェーダを使う場合とは違ったのですかね どちらの方が効率が良いかは実際にどちらのパターンも組んで比べるのが良いと思います CPU負荷が低くて余裕があるのにGPU負荷が高くて高速化が限界に達していたらご紹介のページの解説のように シェーダ切り替えの頻度を増やして軽いシェーダを使うようにするべきですし、逆にGPU負荷が低くて 余裕があるのにCPU負荷が高くて高速化が限界に達していたら重い代わりに多機能なシェーダを使用して CPU負荷を減らすべきです > tan、binormはfloat3でしょうか? はい > また、sposはどのように4次元ベクトルを渡せばいいのかわかりません > Vertex[].spos = なんとすれば良いのでしょうか > Vertex[].spos.x =、.y、.z、.wとそれぞれ代入するしか無いでしょうか 一応 VGet のような関数 F4Get というのがあります DxLib.h で検索してみてください
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.11 )
名前:ffm8 日時:2013/07/07 04:15

お礼が遅れてしまい申し訳ありません おかげさまで随分と高速化を実現することが出来ました。長々とお付き合い頂き本当にありがとうございます MMEのパーティクル系エフェクトのfxファイルなどを読むと xファイルに(0.1,0.1,z)、(-0.1,0.1,z)、(0.1,-0.1,z)、(-0.1,-0.1,z)といった頂点情報(zにはインデックス番号)を15000パーティクル分用意し、 それらのポリゴンの頂点をの座標はzに代入したインデックスと経過時間を代入した定数を利用して頂点シェーダで決めているようでして これは単にMMDの不自由さを補うためにこのような手法を使っているに過ぎないと考えていたのですが、 ttp://hpcgi2.nifty.com/natupaji/bbs/patio.cgi?mode=view&no=2638 こちらのログのNo.4では >GPUが頂点シェーダーに対応している場合はモデルの頂点データは予めVRAMに置いておくので、 >GPUが直ぐにアクセスして頂点計算をして描画することが出来るのですが、 >DrawPolygonIndexed3D で描画する場合は頂点データがシステムメモリにあるので、 >それをまずVRAMに転送してからGPUがそれにアクセスして描画という手順を踏むことになりその分遅くなります とあり、速度に影響するのではないかと考え始めました 様々な部分のコーディングを見直し、個別に負荷を見直していったところ、3〜5万パーティクルまで55〜60fps程度を維持できるようになったのですが、 この辺りから大きなボトルネックになっているのはDrawPolygonIndexed3DToShaderに渡すためのvertexとindexへの代入処理ということが分かりました そのために頂点バッファとインデックスバッファで、初めに書いたようなMMEの手法を真似て GPU上ですべての処理が行えれば劇的な高速化が望めるのではないかと考えているのですが、 その上でいくつか質問があります。 1.DrawPolygonIndexed3DToShaderのvertexとindexは配列数が65535まで、と型によるサイズの制約がありますが 頂点バッファとインデックスバッファはサイズの制約などはありますでしょうか?それともVRAMの容量限界まででしょうか? 2.また、シェーダ処理の上で、処理中の頂点以外の頂点からデータを参照することは出来ませんでしょうか? 3.新たなパーティクルが生成されるたびに毎フレームバッファに転送しては本末転倒なので、 VRAM上でのバッファの末尾にデータを追加するような形でVRAMに渡すということは出来ませんでしょうか? もしも以上3つが出来るなら実装も現実的になりそうですが……やっぱり無理ですかね?
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.12 )
名前:管理人 日時:2013/07/08 09:37

> 1.DrawPolygonIndexed3DToShaderのvertexとindexは配列数が65535まで、と型によるサイズの制約がありますが > 頂点バッファとインデックスバッファはサイズの制約などはありますでしょうか?それともVRAMの容量限界まででしょうか? 制約はあります 最近のグラフィックカードではゲーム向けで0xFFFFFF( 16777215 )個、Intelなどのオンボード系では 0xFFFFF( 1048575 )個が 一度に扱える頂点データの数や一度に描画できるプリミティブ( ポリゴン等 )の数の限界のようです ( GeForce も 7000世代までは 0xFFFFF( 1048575 )個が限界だったようです ) > 2.また、シェーダ処理の上で、処理中の頂点以外の頂点からデータを参照することは出来ませんでしょうか? できません > 3.新たなパーティクルが生成されるたびに毎フレームバッファに転送しては本末転倒なので、 > VRAM上でのバッファの末尾にデータを追加するような形でVRAMに渡すということは出来ませんでしょうか? 頂点バッファとインデックスバッファとオリジナルシェーダーを使用したポリゴンを描画するための関数の一つである DrawPrimitiveIndexed3DToShader_UseVertexBuffer2 では描画に使用する頂点データやインデックスデータの範囲を 引数で指定できるようになっていますので、最初に大きな頂点バッファとインデックスバッファを作成して、 使用する範囲を管理して DrawPrimitiveIndexed3DToShader_UseVertexBuffer2 で実際に描画する際は使用している 部分のみを描画するようにすれば恐らくffm8さんが望まれる処理が実現できると思います あと、既存のバージョンではインデックスバッファに 16bitタイプ( 頂点インデックス配列を WORD 型の配列で指定するタイプ )しか 指定できないようになっていましたので、32bitタイプ( 頂点インデックス配列を DWORD 型の配列で指定するタイプ )を追加しました よろしければこちらをお使いください http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibGCC_DevCppTest.exe // Dev-C++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibGCC_MinGWTest.exe // MinGW 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibDotNet.zip // .NET用 http://homepage2.nifty.com/natupaji/DxLib/DxLibMakeTest.exe // ソース (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』を、VCをお使いの場合は『リビルド』を、 Dev-C++をお使いの方は「Rebuild All(Ctrl+F11)」をして下さい) 32bitタイプのインデックスバッファを作成する場合は、CreateIndexBuffer の第二引数に DX_INDEX_TYPE_32BIT を渡してください そして、実際にインデックスデータをセットする SetIndexBufferData の第二引数には DWORD 型の配列を渡してください
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.13 )
名前:ffm8 日時:2013/07/13 03:04

お返事ありがとうございます。 1.について 処理能力を考えれば事実上制限になりそうにないですね しかしプリミティブ数の限界などまったく考えたことがなかったので、大いに参考になりました、ありがとうございます 2.について やはり無理ですか そうなると使わないダミーの頂点データを作ってそこに運動・展開用のパラメータを置いておくようなことは出来ませんね floatが16個しか渡せないのでパラメータの吟味が必要になりそうです…… パラメータを豊富に持たせて、運動・展開は個別のパラメータを使って、 パーティクルの種類によらず100種類でも200種類でも一般的に同じ処理で行うという方向で書いていたのですが やはりパーティクルの種類ごとにシェーダを書いて個別に処理するほうがいいんでしょうかね なんだかCPUとGPUの関係に似ています。ハードウェアの方向性にソフトウェアも習えということでしょうか 3.について 各関数の使い方などが分かっておらず理解するのに時間がかかりましたが、 恐らく出来るのではないかと、手応えを感じられました 一つ課題があるとすれば、パーティクルの寿命は種類によって異なりますので、 連続な領域が時間が経つにつれてどんどん断片化していくと思われます なのでこれの整理の方法を、バッファの再転送を避けて考える必要がありそうです 4.(新規)半ば諦めていたのですが、おかげさまで随分と実装が現実的になってきました しかし 2.で挙げたパラメータ数の制限は非常に大きな壁となります 私の環境では大きなボトルネックとなっているのは描画のための配列への代入です それを避けるためにバッファでデータを保持することで、新しいパーティクルの生成の際の代入以外をカットできるため、 毎フレーム3〜5万以下のパーティクル生成ならボトルネックにならなさそうです しかしこのままではエフェクト作りの自由度が狭まりますので、また、毎フレームの生成数は増えても数千程度だと思いますので APU的発想で、 自由度は高いですが毎フレームの座標更新による代入がボトルネックとなるDrawPolygonIndexed3Dと 自由度は低いですがGPUの性能次第で圧倒的に数が稼げるDrawPrimitiveIndexed3DToShader_UseVertexBuffer2を 組み合わせて、複雑な運動と展開が必要なパーティクルと 単純な運動・展開で充分なパーティクルとを使い分けてみてはどうかと考えました はい。質問です。 DrawPolygonIndexed3DとDrawPrimitiveIndexed3DToShader_UseVertexBuffer2、やっぱり競合しますでしょうか?
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.14 )
名前:ffm8 日時:2013/07/13 19:19

質問を訂正しておきます DrawPolygonIndexed3Dと、 DrawPrimitiveIndexed3DToShader_UseVertexBuffer2を毎フレーム1回バッファに転送するのと、 では速度は同じと考えてよろしいでしょうか? 同じであるならDrawPolygonIndexed3DとDrawPrimitiveIndexed3DToShader_UseVertexBuffer2を使い分ける必要はなく、 2つ以上のバッファハンドルを確保しておいて片方は4万程度の低容量で毎フレームバッファに転送し、 もう片方は出来るだけバッファに保持しておき、代入負荷を軽減することができそうです あとの問題はは断片化した場合の対処だけですね バッファへの転送は大きいデータを一括で転送しないと、小さいデータを複数回転送していては遅くなりますよね? これがもし大差無いなら全ての問題が解決するのですが……
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.15 )
名前:管理人 日時:2013/07/15 15:48

float16個では足りないとのことですが、具体的にはどのようなパラメータがあるのでしょうか? > DrawPolygonIndexed3Dと、 > DrawPrimitiveIndexed3DToShader_UseVertexBuffer2を毎フレーム1回バッファに転送するのと、 > では速度は同じと考えてよろしいでしょうか? > DrawPrimitiveIndexed3DToShader_UseVertexBuffer2を毎フレーム1回バッファに転送する こちらの場合毎回「転送してから描画」なのに対して > DrawPolygonIndexed3D こちらは転送と描画を一度に行うので、毎回転送する場合は DrawPolygonIndexed3D の方が 高速である可能性はあります ただ、私も試したことは無いので実際にはどちらが高速かはテストプログラムなどで 試していただくのが一番だと思います
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.16 )
名前:ffm8 日時:2013/07/29 00:18

>float16個では足りないとのことですが、具体的にはどのようなパラメータがあるのでしょうか? 少し長くなるのですが、私は以前に2年ほどの間、市販品のゲームの内部メモリをひたすら弄り続けていた時期がありまして、 生成するパーティクルのパラメーターを弄ることができるようになり、 エフェクトの改変やシステムの追加などをして別のゲームとして作り、成果としていくつか動画を上げていた事があるのですが、 その際にパーティクルのパラメーターを調べていくと 連続生成数 連続生成間隔 合成方式 テクスチャナンバー 寿命 展開時間 座標(3軸) 生成時の座標のランダム幅(3軸) 初速(1成分) 加速度(1成分) 最高速度(1成分) 初速ベクトルの拡散角(x,y2成分) 初期角(3軸) 自転速度(3軸) 基本サイズ(3軸) 基本色(unsigned char×4色) サイズ展開率(パーセンテージで管理、unsigned char×3軸) ×(初期、中間1、中間2、終端の4セット) サイズ展開時間(unsigned char×3軸) ×(初期、中間1、中間2、終端の4セット) 色展開率(パーセンテージで管理、unsigned char×4色) ×(初期、中間1、中間2、終端の4セット) 色展開時間(unsigned char×4色) ×(初期、中間1、中間2、終端の4セット) 様々なフラグ(16個程度) 他パーティクルとのリンク ぱっと思い出せるだけでもこのようなパラメータからパーティクルを生成していたようで、 内部メモリのプロの調整したパラメータを読んでいると非常に感心させられ、ひたすら内部メモリを弄り続けていました gifアニメに頼るのではなく、運動や展開で綺麗なエフェクトを作るのが、ゲーム作りと同じかもしくはそれ以上に実現したいことでして、 PSPのスペックでは体感で100〜200個程度のパーティクルしか管理できなかったことや、昔不便に感じた部分も拡張して、PCのスペックで自由にエフェクトを作りたいので、 生成時に纏めてしまえるものを考えても最低でもそれぞれのパーティクルに時間,座標,角度,初期サイズ,終端サイズ初期色,終端色展開率のパラメータは持たせたいところです もちろん持てるパラメータは増えればそれだけいいものになると思いますが 各々にシェーダを書けばエフェクトの種類ごとの定数としてシェーダに置いておけるパラメータも増えますので、これからの方向性次第で練るべき場所だと思います 酷く個人的な話をしてしまい申し訳ありません >テストプログラムなどで試していただくのが一番だと思います 速度計測を行おうと色々試行錯誤していたのですが結局理解不足のために不確定な部分が多く、途中ながら質問させて頂いてもよろしいでしょうか 一応途中ながら結果を先に示しておきます 描画対象をカメラ視野外にして10000または80000パーティクルの描画処理を計測(Release) (描画対象を無限遠に置いた(NearFarの範囲内)時と視野外がほとんど同程度の処理時間だったのと、 1万枚のパーティクルが重なっているので計算するピクセル数が多いとGPUがすぐにボトルネックになるため) 一はVertexとIndexへの代入処理のみ 二はVertexとIndexへの代入処理後、DrawPolygonIndexed3DToShaderの呼び出し 三はVertexとIndexへの代入処理後、SetVertexBufferDataとSetIndexBufferDataでVRAMへ渡す(1万個一括)のみ 四はVertexとIndexへの代入処理後、SetVertexBufferDataとSetIndexBufferDataでVRAMへ渡し(1万個一括)、DrawPolygonIndexed3DToShader_UseVertexBufferの呼び出し 五はVertexとIndexへの代入処理の一つ一つが終わるたびにSetVertexBufferDataとSetIndexBufferDataでVRAMへ渡す(1万個を小分けに1万回)のみ 六はVertexとIndexへの代入処理の一つ一つが終わるたびにSetVertexBufferDataとSetIndexBufferDataでVRAMへ渡し(1万個を小分けに1万回)、DrawPolygonIndexed3DToShader_UseVertexBufferの呼び出し また、ここでの8万パーティクルの描画は(1万代入→1万描画)を8回繰り返しただけのものです そのためバッファありではDX_INDEX_TYPE_32BITのおかげで、もっと四の結果は三に近づくと思われます 一は (VERTEX3D型時) 1万時 1000±10μ秒 59.6fps CPU14% 8万時 7190±10μ秒 59.2fps CPU24% 備考:CPUの負荷は1コアに集中 (VERTEX3DSHADER型時) 1万時 1180±10μ秒 59.6fps CPU15% 8万時 8460±10μ秒 59.0fps CPU27% 備考:CPUの負荷は1コアに集中せず 二は(VERTEX3DSHADER型時) 1万時 1580±10μ秒 59.6fps CPU16% 8万時 11230±40μ秒 54.2fps CPU28% 備考:CPUの負荷は1コアに集中せず 三は(VERTEX3D型時) 1万時 1310±10μ秒 59.6fps CPU15% 8万時 9500±20μ秒 59.5fps CPU28% 備考:CPUの負荷は1コアに集中 四は(VERTEX3D型時) 1万時 2060±10μ秒 59.6fps CPU15% 8万時 17820±50μ秒 40.1fps CPU27% 備考:CPUの負荷は1コアに集中 VERTEX3D型への代入よりもVERTEX3DSHADER型への代入が重い傾向があるようですが、それでもやはりDrawPolygonIndexed3DToShaderで一括処理の方が軽いようですね その差は現状では1.5倍ほどとそれなりに大きいですが、8万一括になるとどの程度軽くなるのかも興味深いところですので、認識を深めてからまた計測したいと思います また、五、六については下記の質問で触れたいと思います 質問 1.作成するバッファのサイズは未使用の部分が無いようにとる必要が有るのでしょうか そんなことはないと考えていたのですが、例えば、ttp://hpcgi2.nifty.com/natupaji/bbs/patio.cgi?mode=view&no=2638 こちらのNo.6前半のサンプルコードのバッファ作成部分を // 4頂点分の頂点バッファを作成 VertexBufHandle = CreateVertexBuffer( 40, DX_VERTEX_TYPE_NORMAL_3D ) ; // 6個分のインデックスバッファを作成 IndexBufHandle = CreateIndexBuffer( 60, DX_INDEX_TYPE_16BIT ) ; などのように4から40や6から60など、大きい値に変更するだけで私の環境では描画されなくなりました これはどういった理由によるものなのでしょうか? 2.サンプルではSetVertexBufferDataにVERTEX3D型を用いているようですが、VERTEX3DSHADER型にすると描画されません これは対応していないのでしょうか?spos,tan,binormが使えないとなるとfloat数がまた減ってしまいますので…… 3.非常に基本的な知識だと思われるのですが、ポリゴンとプリミティブの違いとは何でしょうか? 調べてもこれと言ったものが見当たりませんでしたので……お手数ですが簡単にでいいのでお願いします 4.DrawPrimitive系の関数のint PrimitiveTypeとは何なのでしょうか?3.が理解出来ればなんてこと無いのかもしれませんが…… また、DX_PRIMTYPE_TRIANGLELIST以外にも5つのポリゴン描画タイプがあるようですが、これらを用いてVertexBufHandleの単位分けをしているのでしょうか?(3頂点ポリゴンとして、など) 5.DrawPrimitiveIndexed3DToShader_UseVertexBuffer2の第四引数、int BaseVertexとは何でしょうか? どのような値を入れてやればいいのか皆目見当がつきません、お願いします 6.SetVertexBufferDataなどは、SetVertexBufferData(a,Vertex+b,c,VertexBufHandle)とすると ハンドルをこのように書くのは語弊があるかもしれませんが VertexBufHandle[a]の位置を始点にVertex[0+b]〜Vertex[0+b+c]のデータを渡す、というイメージ付けで間違っておりませんでしょうか? また、上記計測の五、六についてなのですが、SetVertexBufferDataなど、VRAMへ渡す際に、渡した範囲以外は初期化されるというような仕様もありませんよね? VertexとIndexに代入後、代入した範囲をVRAMへ渡す、といった処理を1万回繰り返した後、描画しているのですが 描画結果が恐らく1枚分しか描画されていません(他では1万枚重なっているのですが、明らかに1枚分の薄さ)。また、処理速度も一応以下の様な結果になったのですが 明らかに1枚分程度の負荷しか掛かっておらず、測りたいものを計測できていません 五は 1万時 1250±10μ秒 59.6fps CPU15% 8万時 8880±10μ秒 59.1fps CPU27% CPUの負荷は1コアに集中 六は 1万時 1300±20μ秒 59.6fps CPU15% 8万時 8930±20μ秒 59.1fps CPU27% CPUの負荷は1コアに集中 一応DrawPrimitive3DToShader_UseVertexBuffer2を使って、VertexBufHandle[a]のaが0始点1枚分や、39996始点1枚分などが描画されることから、 各要素にきちんと渡されていることを確認したのですが…… 他の疑問が解決されれば検討の幅も広がるのですが少し頼らせて頂きたいと思います なにか原因の思い当たる部分はありますでしょうか?
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.17 )
名前:管理人 日時:2013/08/03 17:19

ご質問にご返答します > 1.作成するバッファのサイズは未使用の部分が無いようにとる必要が有るのでしょうか 未使用の部分があっても大丈夫です ただ、未使用の部分がある場合は DrawPrimitiveIndexed3D_UseVertexBuffer2 を使用して 使用したい部分だけで描画するように指定する必要があります ( DrawPrimitiveIndexed3D_UseVertexBuffer では未使用の部分も描画処理で使用されてしまうので ) > 2.サンプルではSetVertexBufferDataにVERTEX3D型を用いているようですが、VERTEX3DSHADER型にすると描画されません > これは対応していないのでしょうか?spos,tan,binormが使えないとなるとfloat数がまた減ってしまいますので…… サンプルとは http://hpcgi2.nifty.com/natupaji/bbs/patio.cgi?mode=view&no=2638 こちらのスレッドの プログラムのことでしょうか? こちらのサンプルで VERTEX3DSHADER を使用する場合は CreateVertexBuffer の第二引数を DX_VERTEX_TYPE_SHADER_3D にして、 且つ描画に使用する関数を DrawPrimitiveIndexed3DToShader_UseVertexBuffer などのシェーダーでの描画関数に変更する必要があります > 3.非常に基本的な知識だと思われるのですが、ポリゴンとプリミティブの違いとは何でしょうか? ポリゴンもプリミティブの一つです 点( ポイント )や線( ライン )や三角形( ポリゴン )などすべて「プリミティブ」です ポリゴンやラインなどの総称だと思っていただいて問題ないと思います > 4.DrawPrimitive系の関数のint PrimitiveTypeとは何なのでしょうか?3.が理解出来ればなんてこと無いのかもしれませんが…… 描画するものを「点」にするか「線」にするか「三角形」にするかを指定する引数で、以下のタイプがあります DX_PRIMTYPE_POINTLIST // ポイントリスト DX_PRIMTYPE_LINELIST // ラインリスト DX_PRIMTYPE_LINESTRIP // ラインストリップ DX_PRIMTYPE_TRIANGLELIST // トライアングルリスト DX_PRIMTYPE_TRIANGLESTRIP // トライアングルストリップ DX_PRIMTYPE_TRIANGLEFAN // トライアングルファン MSDNのこちらのページに各プリミティブタイプの解説がありますので、よろしければご覧ください http://msdn.microsoft.com/ja-jp/library/bb147291(v=vs.85).aspx 現在では DX_PRIMTYPE_TRIANGLELIST と DX_PRIMTYPE_POINTLIST と DX_PRIMTYPE_LINELIST 以外は殆ど使用されていないと思います > 5.DrawPrimitiveIndexed3DToShader_UseVertexBuffer2の第四引数、int BaseVertexとは何でしょうか? インデックスバッファで頂点のインデックス( 番号 )を指定しますが、その番号の0番の頂点バッファ側での位置を指定するための引数です 例えば BaseVertex に 100 を渡すと、インデックスバッファのある値が 5 となっていたら、参照される頂点データは 頂点バッファ中の 105番目の頂点ということになります > 6.SetVertexBufferDataなどは、SetVertexBufferData(a,Vertex+b,c,VertexBufHandle)とすると > ハンドルをこのように書くのは語弊があるかもしれませんが > VertexBufHandle[a]の位置を始点にVertex[0+b]〜Vertex[0+b+c]のデータを渡す、というイメージ付けで間違っておりませんでしょうか? はい、間違っていません > また、上記計測の五、六についてなのですが、SetVertexBufferDataなど、VRAMへ渡す際に、渡した範囲以外は初期化されるというような仕様もありませんよね? > VertexとIndexに代入後、代入した範囲をVRAMへ渡す、といった処理を1万回繰り返した後、描画しているのですが > 描画結果が恐らく1枚分しか描画されていません(他では1万枚重なっているのですが、明らかに1枚分の薄さ)。また、処理速度も一応以下の様な結果になったのですが > 明らかに1枚分程度の負荷しか掛かっておらず、測りたいものを計測できていません すみません、ライブラリ側のバグでバッファ全体にデータを転送する以外の引数を指定した場合 SetIndexBufferData も SetVertexBufferData も正常に動作しないようになっていました 修正版をアップしましたので、申し訳ありませんがこちらをお使いください m(_ _;m http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibGCC_DevCppTest.exe // Dev-C++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibGCC_MinGWTest.exe // MinGW 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibDotNet.zip // .NET用 http://homepage2.nifty.com/natupaji/DxLib/DxLibMakeTest.exe // ソース (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』を、VCをお使いの場合は『リビルド』を、 Dev-C++をお使いの方は「Rebuild All(Ctrl+F11)」をして下さい) 頂点データに代入するパラメータの数を減らす方法ですが、そぼろさんのMME用のパーティクル( Blizzard )が参考になると思います https://skydrive.live.com/?cid=a17ecb6418a4b2d1&id=A17ECB6418A4B2D1%21134&sc=documents こちらのエフェクトでは「パーティクルの座標を毎フレーム頂点データに代入して頂点シェーダーに渡す」ということは していません( というか MME の仕様上できない? ) 頂点シェーダーには「パーティクルのインデックス」と「経過時間」だけが渡され、そこから「初期座標」を ランダム値生成用のテクスチャの色値とパーティクルのインデックスから算出して、そこに定数として設定されている 速度などのパラメータと経過時間から現在のフレームでの座標を算出しています これと同じ手法を使えば挙げて頂いた殆どのパラメータを頂点シェーダーの定数に設定してしまえるので、 「毎フレーム頂点バッファの内容を変更する」という必要がなくなるのではないでしょうか?
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.18 )
名前:ffm8 日時:2013/08/17 23:30

お返事が遅れてしまいました、すみません おかげ様で関数の使い方の疑問点は解消されました、ありがとうございます せっかくですので前回の実験の続きをやってみました 一はVertexとIndexへの代入処理のみ 二はVertexとIndexへの代入処理後、DrawPolygonIndexed3DToShaderの呼び出し 三はVertexとIndexへの代入処理後、SetVertexBufferDataとSetIndexBufferDataでVRAMへ渡す(1万個一括)のみ 四はVertexとIndexへの代入処理後、SetVertexBufferDataとSetIndexBufferDataでVRAMへ渡し(1万個一括)、DrawPolygonIndexed3DToShader_UseVertexBufferの呼び出し 五はVertexとIndexへの代入処理の一つ一つが終わるたびにSetVertexBufferDataとSetIndexBufferDataでVRAMへ渡す(1万個を小分けに1万回)のみ 六はVertexとIndexへの代入処理の一つ一つが終わるたびにSetVertexBufferDataとSetIndexBufferDataでVRAMへ渡し(1万個を小分けに1万回)、DrawPolygonIndexed3DToShader_UseVertexBufferの呼び出し 新規 七は最初に一回だけ初期化処理としてSetVertexBufferDataとSetIndexBufferDataでVRAMへ1万個一括で渡しておいて、その後毎フレームDrawPolygonIndexed3DToShader_UseVertexBufferで一括描画。計測は毎フレーム部分のみ また、ここでの8万パーティクルの描画は(1万代入→1万描画)を8回繰り返しただけのものです そのためバッファありではDX_INDEX_TYPE_32BITのおかげで、もっと四の結果は三に近づくと思われます 一は (VERTEX3D型時) 1万時 1000±10μ秒 59.6fps CPU14% 8万時 7190±10μ秒 59.2fps CPU24% 備考:CPUの負荷は1コアに集中 (VERTEX3DSHADER型時) 1万時 1180±10μ秒 59.6fps CPU15% 8万時 8460±10μ秒 59.0fps CPU27% 備考:CPUの負荷は1コアに集中せず 二は(VERTEX3DSHADER型時) 1万時 1580±10μ秒 59.6fps CPU16% 8万時 11230±40μ秒 54.2fps CPU28% 備考:CPUの負荷は1コアに集中せず 三は(VERTEX3D型時) 1万時 1310±10μ秒 59.6fps CPU15% 8万時 9500±20μ秒 59.5fps CPU28% 備考:CPUの負荷は1コアに集中 四は(VERTEX3D型時) 1万時 2060±10μ秒 59.6fps CPU15% 8万時 17820±50μ秒 40.1fps CPU27% 備考:CPUの負荷は1コアに集中 以下新規 五は 1万時 27700±100μ秒 28.8fps CPU28% 備考:CPUの負荷はまばらで1コアに集中せず 8万時 220500±500μ秒 4.4fps CPU28% 備考:CPUの負荷はまばらで1コアに集中せず 六は 1万時 38000±10μ秒 22.2fps CPU24% 備考:CPUの負荷は1コアに集中の傾向、ただし最高負荷のコアの使用率は40〜60%程度、GPUは30%程度 8万時 304094±500μ秒 3.2fps CPU22% 備考:CPUの負荷は1コアに集中の傾向、ただし最高負荷のコアの使用率は40〜60%程度、GPUは40%程度 七は 1万時 51±3μ秒 59.6fps CPU13% 備考:CPUの負荷は1コアに集中、最高負荷のコアの使用率は30〜40%程度、GPUは60%程度 8万時 115±3μ秒 10.3fps CPU6% 備考:CPUの負荷はどのコアもほぼ0、GPUは100% 8万パーティクルは他と同じように近づけるため1万代入→1万描画×8回としました。 1万時のDrawPolygonIndexed3DToShader_UseVertexBuffer部分を8行並べただけで、計測部分は描画関数部分のみ、計測外で毎フレーム実行するのは平均の計算や数値の描画だけですが…… こんなにfpsが落ちているのに処理時間が短いのはGPU側の処理が終わらなくとも描画関数自体は終わって次の処理へ行ってるってことですかね よく考えればGPUの恩恵が得られるのはこうやって並列処理が出来るからですね 予想はしていましたが毎パーティクルVRAMへ渡すと想像以上に重たいです ちなみに三、四の倍程度の負荷まで目をつぶるとすると、毎フレーム3〜5回程度VRAMへ渡せるようです しかし毎フレーム渡すならばDrawPolygonIndexed3DToShaderの方が2/3程度の負荷しかかからないのでバッファ系関数を使うのは全く意味ないですね 毎フレーム渡すのではなく、何らかの初期化の際にVRAMへ渡しっぱなしというのであれば、やはりバッファ系関数の効果は絶大です。ここまでとは思いませんでした 一応今回の実験では20〜70倍の速度ということになりますね >頂点データに代入するパラメータの数を減らす方法ですが、そぼろさんのMME用のパーティクル( Blizzard )が参考になると思います そうですね、私はビームマンPさんのものを初めに読んだのですが、No.11 で述べたようにやはり経過時間と初期値を生成時に渡し、VRAMとGPUのみでパーティクルを運動・描画させていました しかしこの方法では、No.10 で取り上げたように複数のシェーダを作って、それぞれのパーティクルの種類に個別の定数を与えてやる必要があり、 キャラクターの座標のように、毎フレーム不規則に更新される座標を使った記述ができません(単純な例ではキャラの周りに煙を出すなど)ので、No.16 のようにパーティクルの運動の自由度に影響します そのため、No.13 で触れたように、多少不自由な面を持ちながらも大量に処理することが出来るGPU主体のエフェクトと、 毎フレーム更新するため、任意の全ての座標を用いて運動・展開が可能な、しかし数万個止まりのCPU主体のエフェクト、この2種類を使い分けて記述すると満足のいくものに出来そうである、ということが、 このトピックで試行錯誤させて頂きながら出た結論になるのではないでしょうか 私の頭では関数の使い方すら分からない所があったためにテストも満足に出来ず、管理人様には非常に初歩的な部分から教えていただく部分も多く、話の本筋からズレた部分も多々ありましたが、 随分と理解も深まり、方向性や情報のの整理も出来たために、なんとかこのトピックとしては一旦の終着点にまでたどり着いたのではないかと思います 3ヵ月もの間、読みづらい長文に根気よくお返事して下さり、本当にありがとうございました しかし、最後に1つだけ、質問よろしいでしょうか 上記の結論でも、CPU部分の負荷の大半はほとんどただの代入です そのため、マルチスレッドが有効なのではないかと考えたのですが、 ttp://hpcgi2.nifty.com/natupaji/bbs/patio.cgi?mode=view&no=1693 2010年のこちらのトピックでは、 >DXライブラリを使用したマルチスレッドのプログラムを作成する際に注意すべきことは >・サウンド・画像・モデルの読み込み関数や描画や描画の設定を行う関数を複数のスレッドから同時に呼ばないこと >・入力関係の関数を複数のスレッドから同時に呼ばないこと >・サウンド関係の関数を複数のスレッドから同時に呼ばないこと >です、 と、ありますが現在も特に事情は変わっておりませんでしょうか? また、算術関係の関数は使用しても問題ないということでよろしいでしょうか? 話題が大きく変わり、トピック違いかもしれませんが、長い間居座った挙句、また新しくトピックを作るのは気が引けますので良ければご回答下さい
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.19 )
名前:ffm8 日時:2013/08/18 00:25

すみません大きな間違いをしていました 実験の七についてですが処理落ちの原因は頂点処理ではなくピクセル処理でした 前回と違って8万枚重ねたビルボードが画面に結構大きく映るアングルに変わってしまっていたことを忘れていたので、 ほとんど画面内に入らないアングルで実験しなおしてみました また、fpsについても不要な処理があり、59.6で頭打ちの環境になってますがそれを外せば60.0きちんと出ます 七は 1万時 46±3μ秒 59.6fps CPU13% 備考:CPUの負荷は1コアに集中の傾向、最高負荷のコアの使用率は20〜30%程度、GPUはほとんど負荷なし 10万時 62±3μ秒 59.6fps CPU13% 備考:CPUの負荷は1コアに集中の傾向、最高負荷のコアの使用率は20〜30%程度、GPUはほとんど負荷なし 100万時 110±3μ秒 59.6fps CPU14% 備考:CPUの負荷は平均的に10〜20%程度、GPUは30〜40%程度 300万時 220±3μ秒 59.6fps CPU14% 備考:CPUの負荷は平均的に10〜20%程度、GPUはほぼ100% まだまだ侮っていたようです そりゃCPUが4コアでも50〜200Gflopsに対してGPUは700G〜2Tflopsとかですもんね よくエフェクトが画面を覆ったときに処理落ちするのを見ますが、結局ピクセルあたりの合成回数ですね 近ければ少数でも処理落ちするし、遠ければ多数でも処理落ちしない、と まあこの辺りは作りこんでいったときの、カメラに映るパーティクルとその射影した大きさの時間平均を見ながら調整しかないですね
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.20 )
名前:管理人 日時:2013/08/24 22:41

> と、ありますが現在も特に事情は変わっておりませんでしょうか? はい > また、算術関係の関数は使用しても問題ないということでよろしいでしょうか? はい
メンテ
Re: DrawPolygonIndexed3DToShaderni ( No.21 )
名前:ffm8(解決) 日時:2013/08/25 16:22

よく考えるとGPU側の処理時間を測れていないので上の計測時間は関数呼び出しの時間だけで意味のないものでした このような恥ずかしいトピックに長々とお付き合い下さり本当にありがとうございました これで解決とさせていただきます
メンテ

Page: 1 | 2 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存