主にプログラミング関連のメモ帳 ♪(✿╹ヮ╹)ノ
書いてあるコードは自己責任でご自由にどうぞ。記事本文の無断転載は禁止です。
2022/11/22
いつもは Unity みたいな高レイヤーですが、今回は比較的低レイヤーのお話です。
基本的に、最近の場合は DirectX を直に触るケースは少なくなってて、例えば Unity や Unreal Engine 等のような、ゲームエンジンを触ることがほとんどだと思います。
ただ、細かい処理をしようとしたり、 Windows の内部をごにょごにょしたい場合は、やはり DirectX の知識が必要になります。
ということで、今回は DirectX の Texture2D を Bitmap として取り出す方法です。
まず、 Texture2D を作成します。
作成する Texture2D には、必ず CPUAccessFlags
には Read
を、 Usage
には Staging
を指定する必要があります。
var description = new Texture2DDescription
{
ArraySize = 1,
BindFlags = BindFlags.None,
CPUAccessFlags = CpuAccessFlags.Read, // https://learn.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_cpu_access_flag
Format = Format.B8G8R8A8_UNorm,
Height = 1080,
MipLevels = 1,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Staging, // https://learn.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_usage
Width = 1920,
};
var texture = device.CreateTexture2D(description);
作成したら、適当なテクスチャーをコピーしてきます。
device.ImmediateContext.CopyResource(texture, surface);
コピーしたら、 GPU 上にあるデータを、 CPU 上にコピーします。
var box = device.ImmediateContext.Map(texture, 0);
最後に、コピーしてきたデータを Bitmap に投げつけるだけです。
using var bitmap = new Bitmap(description.Width, description.Height, PixelFormat.Format32bppArgb);
var dest = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, bitmap.PixelFormat);
var copyBytes = bitmap.Width * 4;
for (var y = 0; y < bitmap.Height; y++)
MemoryHelpers.CopyMemory(dest.Scan0 + y * dest.Stride, box.DataPointer + y * box.RowPitch, copyBytes);
bitmap.UnlockBits(dest);
device.ImmediateContext.Unmap(texture, 0);
あとはこの bitmap
を煮るなり焼くなりすれば良いでしょう。
ということで、メモでした。