5

これは、StackOverflow に関する初めての質問です。万歳! 仕事と個人的なプログラミングの謎の両方で、日常的に StackOverflow を使用していると正直に言えます。99.9% の確率で、実際にここでも必要な答えが見つかります。これは素晴らしいことです!

実際に機能するものが見つからないように見えるため、現在の問題は実際には少し困惑しました。私はすでに GameDev.net のいくつかの投稿を読み、ネット上で他のリソースを見つけましたが、それを整理することはできません。

私は XNA 用に書いた小さな 2D エンジンを SlimDX (現時点では DirectX9 のみ) に移植している最中です。 XNA を使用して 6 か月。基本的なレンダリング機能のほとんどを完了し、実際に XNA SpriteBatch を大量の追加機能で再作成することができました (XNA では本当に見逃していました)。

私が仕事に取り掛かろうとしている最後のことの 1 つは、特定のテクスチャからソース四角形を抽出し、それをタイリングに使用することです。理由: タイリングしないときは、UV をいじって表示したいソース (例: 0.3;0.3 から 0.5;0.5) を取得できますが、タイリングするときは UV をタイリングする必要があります (0;0 から 2;2は、画像を 2 回並べることを意味します)、したがって、カットアウト テクスチャが必要です。

長い話を短くするために、私は以下を使用しようとします:

DataRectangle dataRectangle = sprite.Texture.LockRectangle(0, LockFlags.None);
Format format = sprite.Texture.GetLevelDescription(0).Format;

byte[] buffer = new byte[4];
dataRectangle.Data.Read(buffer, ([y] * dataRectangle.Pitch) + ([x] * 4), buffer.Length);
texture.UnlockRectangle(0);

さまざまなピクセルを試しましたが、すべて偽のデータを提供しているようです。たとえば、実際に現在のアバターを使用して、DataRectangle から取得したバッファーが画像内の実際のピクセルと一致するかどうかを確認しようとしましたが、うまくいきませんでした (フォーマットが正しいかどうかも確認しました)。

私は何を間違っていますか?それを行うより良い方法はありますか?または、私の UV ストーリーが間違っているので、タイルを張る前にソース長方形を切り取るよりもはるかに簡単に解決できますか?

お時間をいただきありがとうございます。

レナード・フォンテイン

更新 #1

実際には、バイト配列から次の変換を使用して、ピクセル データをビットマップにエクスポートすることができました。

int pixel = (buffer[0] & 0xFF) | ((buffer[1] & 0xFF) << 8) | ((buffer[2] & 0xFF) << 16) | ((255 - buffer[3] & 0xFF) << 24);

したがって、データは私が思っていたほど偽物ではないようです。ただし、次の問題は、ソースの四角形で指定されたピクセルを取得し、それらを新しいテクスチャにコピーすることです。切り取ろうとしている画像は 150x150 ですが、何らかの理由で 256x256 の画像 (2 のべき乗) に引き伸ばされていますが、実際に 150x150 を超えるピクセルにアクセスしようとすると、OutOfBounds 例外がスローされます。また、実際に 256x256 の 2 つ目の空白のテクスチャを作成しようとすると、何を入れても真っ黒になってしまいます。

これが私の現在のコードです:

//Texture texture = 150x150
DataRectangle dataRectangle = texture.LockRectangle(0, LockFlags.None);
SurfaceDescription surface = texture.GetLevelDescription(0);

Texture texture2 = new Texture(_graphicsDevice, surface.Width, surface.Height, 0, surface.Usage, surface.Format, surface.Pool);
DataRectangle dataRectangle2 = texture2.LockRectangle(0, LockFlags.None);

for (int k = sourceX; k < sourceHeight; k++)
{
    for (int l = sourceY; l < sourceWidth; l++)
    {
        byte[] buffer = new byte[4];
        dataRectangle.Data.Seek((k * dataRectangle.Pitch) + (l* 4), SeekOrigin.Begin);
        dataRectangle.Data.Read(buffer, 0, 4);

        dataRectangle2.Data.Seek(((k - sourceY) * dataRectangle2.Pitch) + ((l - sourceX) * 4), SeekOrigin.Begin);
        dataRectangle2.Data.Write(buffer, 0, 4);
    }
}

sprite.Texture.UnlockRectangle(0);
texture2.UnlockRectangle(0);

_graphicsDevice.SetTexture(0, texture2);

私の新しい (追加の) 質問は次のとおりです。アルファ チャネルを含む、あるテクスチャから別の小さなテクスチャにピクセルを移動するにはどうすればよいですか? 元のテクスチャが 150x150 の場合、SurfaceDescription が 256x256 を報告するのはなぜですか?

4

1 に答える 1

5

私自身の質問に答えるのはちょっと厄介ですが、もう少し掘り下げて簡単な試行錯誤を繰り返した後、解決策を見つけました。

最初に、テクスチャをロードする方法を変更する必要がありました。内部で 2 のべき乗サイズにサイズ変更されないようにするには、次の方法を使用する必要がありました。

Texture texture = Texture.FromFile(_graphicsDevice, [filePath], D3DX.DefaultNonPowerOf2, D3DX.DefaultNonPowerOf2, 1, Usage.None, Format.Unknown, Pool.Managed, Filter.None, Filter.None, 0);

サイズが 2 の累乗でないことを具体的にどのように指定したかに注目してください。

次に、新しいテクスチャ定義に誤りがありました。0 レベルを指定する (そして MipMap を自動生成する) 代わりに、次のように 1 レベルを指定する必要がありました。

Texture texture2 = new Texture(_graphicsDevice, [sourceWidth], [sourceHeight], 1, surface.Usage, surface.Format, surface.Pool);

それを行った後、実際の質問にある for ループは正常に動作します。

DataRectangle dataRectangle = texture.LockRectangle(0, LockFlags.None);
SurfaceDescription surface = texture.GetLevelDescription(0);

DataRectangle dataRectangle2 = texture2.LockRectangle(0, LockFlags.None);

for (int y = [sourceX]; y < [sourceHeight]; k++)
{
    for (int x = [sourceY]; x < [sourceWidth]; l++)
    {
        byte[] buffer = new byte[4];
        dataRectangle.Data.Seek((y * dataRectangle.Pitch) + (x * 4), SeekOrigin.Begin);
        dataRectangle.Data.Read(buffer, 0, 4);

        dataRectangle2.Data.Seek(((y - [sourceY]) * dataRectangle2.Pitch) + ((x - [sourceX]) * 4), SeekOrigin.Begin);
        dataRectangle2.Data.Write(buffer, 0, 4);
    }
}

texture.UnlockRectangle(0);
texture2.UnlockRectangle(0);

_graphicsDevice.SetTexture(0, texture2);

括弧内はすべて、このスニペットの外部からの変数と見なされます。_graphicsDevice は十分に明確だと思います。.Seek を簡略化できることは承知していますが、例としてはうまく機能すると思います。この種の操作をフレームごとに行うことはお勧めしません。間違った使い方をすると FPS が急速に消耗してしまうからです。

理解するのにかなり時間がかかりましたが、結果は満足のいくものです。この質問に目を通し、私を助けようとしてくれたすべての人に感謝します。

レナード・フォンテイン

于 2011-08-12T19:02:52.343 に答える