いつもは 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
を煮るなり焼くなりすれば良いでしょう。
ということで、メモでした。