Cách tôi làm điều này là như sau.
IDirect3DDevice9 :: GetBackBuffer : Truy cập vào IDirect3DSurface9 đại diện cho bộ đệm phía sau, giống như bạn hiện có. Đừng quên Giải phóng bề mặt này khi thực hiện vì cuộc gọi này sẽ tăng số tham chiếu!
IDirect3DSurface :: GetDesc : Nhận mô tả về bề mặt bộ đệm phía sau, sẽ cung cấp cho bạn chiều rộng, chiều cao và định dạng.
IDirect3DDevice9 :: Tạo OfferscreenPlainSurface : Tạo một đối tượng bề mặt mới trong D3DPOOL_SCRATCH; bạn thường muốn sử dụng cùng chiều rộng, chiều cao và định dạng (nhưng thực tế bạn không phải làm theo phương pháp này). Một lần nữa, Phát hành khi hoàn thành. Nếu bạn đang thực hiện thao tác này mọi khung hình (trong trường hợp đó, bạn nên tìm kiếm các giải pháp thay thế như cách tiếp cận dựa trên shader cho những gì bạn đang cố gắng thực hiện), bạn có thể tạo bề mặt phẳng ngoài màn hình một lần khi khởi động và sử dụng lại nó, thay vì tạo ra nó mỗi khung hình.
D3DXLoadSurfaceFromSurface : Sao chép từ bề mặt bộ đệm phía sau sang bề mặt trơn. Điều này sẽ tự động thay đổi kích thước và định dạng cho bạn. Ngoài ra, nếu bạn không muốn hoặc cần thay đổi kích thước hoặc thay đổi định dạng, bạn có thể sử dụng IDirect3DDevice9 :: GetRenderTargetData , nhưng nếu vậy thì hãy tạo bề mặt đơn giản ngoài màn hình trong D3DPOOL_SYIUSMEM thay thế.
IDirect3DSurface9 :: LockRect : Truy cập vào dữ liệu trên bề mặt đơn giản ngoài màn hình và có cách độc ác của riêng bạn với nó; UnlockRect khi hoàn tất.
Mã này trông giống mã hơn rất nhiều nhưng bạn sẽ thấy rằng nó cũng nhanh như glReadPixels, và thậm chí có thể nhanh hơn nếu bạn không cần thực hiện chuyển đổi định dạng (mà glReadPixels sử dụng GL_RGB gần như chắc chắn).
Chỉnh sửa để thêm: một số chức năng của trình trợ giúp (đã sẵn sàng) tôi cũng có thể hữu ích khi sử dụng phương pháp này cho ảnh chụp màn hình:
// assumes pitch is measured in 32-bit texels, not bytes; use locked_rect.Pitch >> 2
void CollapseRowPitch (unsigned *data, int width, int height, int pitch)
{
if (width != pitch)
{
unsigned *out = data;
// as a minor optimization we can skip the first row
// since out and data point to the same this is OK
out += width;
data += pitch;
for (int h = 1; h < height; h++)
{
for (int w = 0; w < width; w++)
out[w] = data[w];
out += width;
data += pitch;
}
}
}
void Compress32To24 (byte *data, int width, int height)
{
byte *out = data;
for (int h = 0; h < height; h++)
{
for (int w = 0; w < width; w++, data += 4, out += 3)
{
out[0] = data[0];
out[1] = data[1];
out[2] = data[2];
}
}
}
// bpp is bits, not bytes
void WriteDataToTGA (char *name, void *data, int width, int height, int bpp)
{
if ((bpp == 24 || bpp == 8) && name && data && width > 0 && height > 0)
{
FILE *f = fopen (name, "wb");
if (f)
{
byte header[18];
memset (header, 0, 18);
header[2] = 2;
header[12] = width & 255;
header[13] = width >> 8;
header[14] = height & 255;
header[15] = height >> 8;
header[16] = bpp;
header[17] = 0x20;
fwrite (header, 18, 1, f);
fwrite (data, (width * height * bpp) >> 3, 1, f);
fclose (f);
}
}
}