スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

DXライブラリで大量モデル描画比較

こんにちは
割とピンキッシュなペチコです

ピンキー

下手なのでレースとか全然クリアしてませんがコレクションはだいすきです
Dolでも船枠がいっぱいあれば並べて楽しめるのに

PC版のTest Drive Unlimited 2ってゲームでこういうピンキーなのを見かけたら多分わたしです


今回はモデル描画でちょっと気になったところのテスト

大量にモデルを描画する際に
・ループで位置を変えながら通常描画する
・モデルのコピーを描画するモデル分作って描画
・全てのモデルを頂点バッファに格納して描画
の計測をやってみました

コードはこんな感じ

#include "DxLib.h"
#include <malloc.h>

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
VERTEX3D *Vertex ;
DWORD *Index ;
int VertexBufHandle ;
int IndexBufHandle ;
int ModelHandle ;
int IndexNum =0;
int VertexNum =0;
int i ;
LONGLONG Time1, Time2 ,Time3;
MV1_REF_POLYGONLIST RefMesh ;

// DXライブラリの初期化
ChangeWindowMode( TRUE ) ;
if( DxLib_Init() < 0 )
{
// エラーが発生したら直ちに終了
return -1 ;
}

// 裏画面を描画対象にする
SetDrawScreen( DX_SCREEN_BACK ) ;

// Zバッファを使用する
SetUseZBufferFlag( TRUE ) ;

// Zバッファへの書き込みを行う
SetWriteZBufferFlag( TRUE ) ;

// バックカリングを行う
SetUseBackCulling( TRUE ) ;

// モデルの読み込み
ModelHandle = MV1LoadModel( "grass.mv1" ) ;
int GraphHandle = LoadGraph( "grass.dds" ) ;

// 参照用メッシュの作成
MV1SetupReferenceMesh( ModelHandle, -1, TRUE ) ;
// 参照用メッシュの取得
RefMesh = MV1GetReferenceMesh( ModelHandle, -1, TRUE ) ;
// 頂点の数とインデックスの数を取得
IndexNum = RefMesh.PolygonNum * 3 * 10000 ;
VertexNum = RefMesh.VertexNum * 10000 ;

// 頂点データとインデックスデータを格納するメモリ領域の確保
Vertex = ( VERTEX3D * )malloc( sizeof( VERTEX3D ) * VertexNum ) ;
Index = ( DWORD * )malloc( sizeof( DWORD ) * IndexNum ) ;

int vnum=0;
int pnum=0;
for(int x=0;x<100;x++){
for(int z=0;z<100;z++){
// 画面に映る位置に3Dモデルを移動
MV1SetPosition( ModelHandle, VGet( x*100.0f, 0.0f, -z*100.0f ) ) ;
// Y軸回転
MV1SetRotationXYZ( ModelHandle, VGet( 0.0f, 60.0f * DX_PI_F / 180.0f, 0.0f ) ) ;

//// 参照用メッシュの作成
//MV1SetupReferenceMesh( ModelHandle, -1, TRUE ) ;
// 参照用メッシュの更新
MV1RefreshReferenceMesh( ModelHandle, -1, TRUE ) ;

// 参照用メッシュの取得
RefMesh = MV1GetReferenceMesh( ModelHandle, -1, TRUE ) ;
// 頂点データをコピー
for( i = 0 ; i < RefMesh.VertexNum ; i ++ )
{
Vertex[ i+vnum ].pos = RefMesh.Vertexs[ i ].Position ;
Vertex[ i+vnum ].norm = RefMesh.Vertexs[ i ].Normal ;
Vertex[ i+vnum ].dif = RefMesh.Vertexs[ i ].DiffuseColor ;
Vertex[ i+vnum ].spc = RefMesh.Vertexs[ i ].SpecularColor ;
Vertex[ i+vnum ].u = RefMesh.Vertexs[ i ].TexCoord[ 0 ].u ;
Vertex[ i+vnum ].v = RefMesh.Vertexs[ i ].TexCoord[ 0 ].v ;
Vertex[ i+vnum ].su = RefMesh.Vertexs[ i ].TexCoord[ 1 ].u ;
Vertex[ i+vnum ].sv = RefMesh.Vertexs[ i ].TexCoord[ 1 ].v ;
}

// インデックスデータをコピー
for( i = 0 ; i < RefMesh.PolygonNum ; i ++ )
{
Index[ i * 3 + 0 + pnum ] = ( WORD )RefMesh.Polygons[ i ].VIndex[ 0 ]+vnum ;
Index[ i * 3 + 1 + pnum ] = ( WORD )RefMesh.Polygons[ i ].VIndex[ 1 ]+vnum ;
Index[ i * 3 + 2 + pnum ] = ( WORD )RefMesh.Polygons[ i ].VIndex[ 2 ]+vnum ;
}
vnum+=RefMesh.VertexNum;
pnum+=RefMesh.PolygonNum*3;
}
}

// 頂点データとインデックスデータを格納する頂点バッファとインデックスバッファを作成
VertexBufHandle = CreateVertexBuffer( VertexNum, DX_VERTEX_TYPE_NORMAL_3D ) ;
IndexBufHandle = CreateIndexBuffer( IndexNum, DX_INDEX_TYPE_32BIT ) ;

// 頂点バッファとインデックスバッファにデータを転送
SetVertexBufferData( 0, Vertex, VertexNum, VertexBufHandle ) ;
SetIndexBufferData( 0, Index, IndexNum, IndexBufHandle ) ;

//モデルのコピー
int D_ModelHandle[10000];
for(int x=0;x<100;x++){
for(int z=0;z<100;z++){
D_ModelHandle[x*100+z]=MV1DuplicateModel( ModelHandle ) ;
// 画面に映る位置に3Dモデルを移動
MV1SetPosition( D_ModelHandle[x*100+z], VGet( x*100.0f, 0.0f, -z*100.0f ) ) ;
// Y軸回転
MV1SetRotationXYZ( D_ModelHandle[x*100+z], VGet( 0.0f, 60.0f * DX_PI_F / 180.0f, 0.0f ) ) ;
// テクスチャ
MV1SetTextureGraphHandle( D_ModelHandle[x*100+z], 0, GraphHandle, TRUE ) ;
//アルファテスト用
MV1SetMaterialDrawAlphaTest(D_ModelHandle[x*100+z],0,TRUE,DX_CMP_GREATER,128) ;
}
}

// 標準ライトの方向をX軸のプラス方向にする
SetLightDirection( VGet( 1.0f, 0.0f, 0.0f ) ) ;

//カメラ
SetCameraPositionAndTarget_UpVecY( VGet( -500.0f, 700.0f, 500.0f ), VGet( 500.0f, 0.0f, -500.0f ) ) ;

//アルファテスト用
SetDrawAlphaTest( DX_CMP_GREATER, 128 ) ;
MV1SetMaterialDrawAlphaTest(ModelHandle,0,TRUE,DX_CMP_GREATER,128) ;

// メインループ
while( ProcessMessage() == 0 )
{
// 画面をクリア
ClearDrawScreen() ;
// 頂点バッファ描画の時間計測
Time1 = GetNowHiPerformanceCount() ;
// 頂点バッファで描画
DrawPolygonIndexed3D_UseVertexBuffer( VertexBufHandle, IndexBufHandle, GraphHandle , TRUE ) ;
Time1 = GetNowHiPerformanceCount() - Time1 ;

// 画面をクリア
ClearDrawScreen() ;
Time2 = GetNowHiPerformanceCount() ;
for(int x=0;x<100;x++){
for(int z=0;z<100;z++){
// 画面に映る位置に3Dモデルを移動
MV1SetPosition( ModelHandle, VGet( x*100.0f, 0.0f, -z*100.0f ) ) ;
// Y軸回転
MV1SetRotationXYZ( ModelHandle, VGet( 0.0f, 60.0f * DX_PI_F / 180.0f, 0.0f ) ) ;
//モデル通常描画
MV1DrawModel( ModelHandle );
}
}
Time2 = GetNowHiPerformanceCount() - Time2 ;

// 画面をクリア
ClearDrawScreen() ;
Time3 = GetNowHiPerformanceCount() ;
for(int x=0;x<100;x++){
for(int z=0;z<100;z++){
// モデルコピー描画
MV1DrawModel( D_ModelHandle[x*100+z] ) ;
}
}
Time3 = GetNowHiPerformanceCount() - Time3 ;

// 掛かった時間を描画
DrawFormatString( 0, 0, GetColor( 255,255,255 ), "頂点バッファ :%4d micro sec", Time1 ) ;
DrawFormatString( 0, 16, GetColor( 255,255,255 ), "通常描画   :%4d micro sec", Time2 ) ;
DrawFormatString( 0, 32, GetColor( 255,255,255 ), "コピー描画  :%4d micro sec", Time3 ) ;

// 裏画面の内容を表画面に反映
ScreenFlip() ;
}

// DXライブラリの後始末
DxLib_End() ;

// ソフトの終了
return 0 ;
}


使用したモデルはこの時やった井形の草メッシュにアルファ抜きしたテクスチャです
別にメッシュはなんでもいいのですが、プログラム側で草を100x100ばらまいたという想定でやってみました

結果の前に簡単な説明
割とてきとうにやったので間違ってるトコとかあるかもしれません。どうぞよしなに

最初の方で参照用メッシュを作ってるのが頂点バッファ用
参照用メッシュから配置する草の数分頂点に突っ込んでいます
ここでは同じモデルが複数なので単純にモデルの頂点数*モデルの数でやってますが、別モデルも同じ頂点系に入れる場合はモデル毎の参照メッシュを作成して頂点数に加算ってやんなきゃダメですね
頂点バッファで扱う場合は、同じテクスチャを使用するマテリアルをまとめるので別モデルにすることは少なそうですが

頂点インデックス(unsigned short)の上限65536を超えてしまったので32bitのDWORDを使ってますが、対応してないグラフィックデバイスもあるそうなので、この数未満に抑えた方がいいのかもですね

通常モデルの描画はメインループ中で位置と回転を設定して100*100DrawModelしてます
使ったテクスチャがアルファ抜きやってますので、モデルのマテリアル毎のアルファテスト(MV1SetMaterialDrawAlphaTest)をやってます

コピーモデル描画は元の通常描画用モデルをMV1DuplicateModelで100*100個コピーしてます
コピーする際に移動回転も行っているので描画部はただDrawModelするだけにしてます
こちらも各コピーモデル毎にアルファテストの設定もやってます


肝心の結果
モデル描画速度比較

頂点バッファ使用:29ms
通常描画    :33366ms
コピー描画   :37042ms

おそろしく差が付きました
頂点数は16万ですが、頂点バッファを使用した時は、モデル一つ(頂点数16)描画(18ms~22ms)するのとほとんど変わりない速度で描画できています
コピー描画はあまりに数が多すぎてVRAM溢れちゃったのかもしれません。512Mしかないもので

草や木や地面などの動かない物体を大量に描画する時は頂点バッファを使うのが良さそうですね


ただ上の方法でモデルから頂点バッファを作成した場合に、ちょっと暗かったり微妙に描画結果が変わるんですよね
どっか間違えてるんでしょうね修正する気はなし


コメントの投稿

非公開コメント

プロフィール

ペチコートさん

Author:ペチコートさん
大航海時代オンライン
Zephyros、Eurosサーバーに潜伏中

偽ペチコ1号・2号
ペチコの手下達
Zephyrosサーバーに潜伏中

最新記事
月別アーカイブ
カテゴリ
リンク
最新コメント
検索フォーム
QRコード
QR
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。