2008年02月05日

Direct3Dでテクスチャのロードを速くする

描画関係をDirec3Dでやるようになってすぐ、プログラムの起動が異様に遅くなった。調べてみるとBitmapからテクスチャを生成する際にえらく時間がかかっていた。うちの環境では512x512のテクスチャ生成するのに40秒以上かかる。Bitmapのコンストラクタや、Graphics.DrawImageでも一瞬で終わるのに・・・。

調べてみると、やっぱりTexture.FromBitmapはあまりにも遅いとの評判だった(内部的にはGDI+のGetPixel→SetPixelをやってるとか。あほか。)。で、じゃあどうやって速くすんねんということで・・・。

ビットマップからテクスチャーを作る-山に生きる
http://d.hatena.ne.jp/pmoky/20040811


↑を参考にさしてもらって、SurfaceからGraphicsを取得し、DrawImageで描画。おお!速い!けど、アルファ入りのフォーマット扱えないのは辛いなあ・・・。

ということで、同じ記事のNyaRuRu氏のコメントを参考に、Bitmap.LockBitsとTexture.LockRectangleを使って、データ丸写しという危ない橋を渡る事に・・・。

以下、Bitmapを元にテクスチャを生成するメソッド。

//テクスチャ読み込みメソッド
Texture LoadTexture(Bitmap src)
{

//Direct3Dのテクスチャの幅・高さは2の累乗でないといけないので、
//元となるBitmapが収まるテクスチャサイズを算出。
int h = 1;
int w = 1;
while (w < src.Width) { w *= 2; }
while (h < src.Height) { h *= 2; }
width = w;
height = h;

//サイズを考慮したBitmapに移す
Bitmap bmp = new Bitmap(w, h);
Graphics g = Graphics.FromImage(bmp);
g.Clear(Color.Transparent);
g.DrawImage(src, 0, 0);
g.Dispose();

//空のテクスチャ用意
Texture tex = new Texture(dev,w,h,0,Usage.Dynamic,Format.A8R8G8B8,Pool.Default);

//上記テクスチャをロック
//Bitmapのデータとタテヨコが逆になってるようなのでHeight、Widthの順
SurfaceDescription desc = tex.GetLevelDescription(0);
UInt32[,] buf = (UInt32[,])tex.LockRectangle(typeof(UInt32), 0,
LockFlags.None, desc.Height, desc.Width);

//元となるBitmapをロックしてbyteの配列に移す
BitmapData bmpdata = bmp.LockBits(new Rectangle(0,0,w , h),ImageLockMode.ReadWrite,PixelFormat.Format32bppArgb);
IntPtr ptr = bmpdata.Scan0;
byte[] temp = new byte[bmpdata.Width * bmpdata.Height * 4];
Marshal.Copy(ptr,temp,0,bmpdata.Width * bmpdata.Height * 4);
//データ取得できたのでBitmapアンロック
bmp.UnlockBits(bmpdata);

//取得したBitmapのデータをテクスチャに移す
for (int y = 0; y <= bmpdata.Height - 1; y++)
{
for (int x = 0; x <= bmpdata.Width - 1; x++)
{
//Byte×4をUInt32×1にしつつ、
//タテ・ヨコを逆にしてコピーしていく
buf[y,x] = (UInt32)temp[y * bmpdata.Width * 4 + x * 4]
+ (UInt32)temp[y * bmpdata.Width * 4 + x * 4 + 1] * 256
+ (UInt32)temp[y * bmpdata.Width * 4 + x * 4 + 2] * 65536
+ (UInt32)temp[y * bmpdata.Width * 4 + x * 4 + 3] * 256 * 65536;
}
}

//テクスチャをアンロック
tex.UnlockRectangle(0);

return tex;
}

例外処理とか一切無いので注意。
なお、昨日アップしたファイルでは、サイズの変更が片手落ちだったので、新しいのをアップしときます。

PenzSDK20080205.cs
posted by ラボ長 at 23:52| Comment(0) | TrackBack(0) | プログラミング | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。

この記事へのトラックバック