我正在试图挂钩DirectX游戏。我成功加载了我的钩子,我可以使用以下方法将图像/后备缓冲区保存到磁盘:
HRESULT Capture(IDirect3DDevice9* Device, const char* FilePath)
{
IDirect3DSurface9* RenderTarget = nullptr;
HRESULT result = Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &RenderTarget);
//for some reason result is never S_OK but this still works.
result = D3DXSaveSurfaceToFile(FilePath, D3DXIFF_PNG, RenderTarget, nullptr, nullptr);
SafeRelease(RenderTarget);
return result;
}
成功保存,我很高兴。但是,我想保存到像素阵列而不是磁盘。我尝试使用:
#include <memory>
std::unique_ptr<std::uint8_t[]> mem(new std::uint8_t[100 * 100 * 4]);
HRESULT Direct3DDevice9Proxy::EndScene()
{
IDirect3DSurface9* RenderTarget = nullptr;
HRESULT result = ptr_Direct3DDevice9->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &RenderTarget);
D3DLOCKED_RECT LR;
RenderTarget->LockRect(&LR, nullptr, D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY);
memcpy(mem.get(), LR.pBits, LR.Pitch - 1);
RenderTarget->UnlockRect();
SafeRelease(RenderTarget);
return ptr_Direct3DDevice9->EndScene();
}
但是,它永远不会锁定,如果我尝试访问LR.pBits,它会抛出访问冲突。我不确定为什么它不会锁定。还有另一种方法可以将后备缓冲区中的像素抓取到字节数组中吗?游戏的最大视口为1366x768。
编辑:我试过了:void dump_buffer(LPDIRECT3DDEVICE9 Device, std::unique_ptr<std::uint8_t[]> &bits)
{
IDirect3DSurface9* RenderTarget = nullptr;
IDirect3DSurface9* DestTarget = nullptr;
D3DSURFACE_DESC rtDesc = {};
Device->GetRenderTarget(0, &RenderTarget);
RenderTarget->GetDesc(&rtDesc);
Device->CreateOffscreenPlainSurface(rtDesc.Width, rtDesc.Height, rtDesc.Format, D3DPOOL_DEFAULT, &DestTarget, nullptr);
Device->GetRenderTargetData(RenderTarget, DestTarget);
if(DestTarget != nullptr)
{
D3DLOCKED_RECT rect;
DestTarget->LockRect(&rect, 0, D3DLOCK_READONLY);
memcpy(bits.get(), rect.pBits, rtDesc.Width * rtDesc.Height * 4);
std::uint8_t* ptr = &bits[0];
CG::Image(ptr, rtDesc.Width, rtDesc.Height).Save("Foo.bmp");
DestTarget->UnlockRect();
DestTarget->Release();
}
RenderTarget->Release();
}
HRESULT Direct3DDevice9Proxy::EndScene()
{
dump_buffer(ptr_Direct3DDevice9, mem);
return ptr_Direct3DDevice9->EndScene();
}
但我的形象是黑色的。有什么想法吗?
答案 0 :(得分:1)
有点晚了。但希望这对某人有帮助。
创建
if (SUCCEEDED(hr = _device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuf)))
{
D3DSURFACE_DESC sd;
backBuf->GetDesc(&sd);
if (SUCCEEDED(hr = _device->CreateOffscreenPlainSurface(sd.Width, sd.Height, sd.Format, D3DPOOL_SYSTEMMEM, &_surface, NULL)))
捕获
if (SUCCEEDED(hr = _device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuf)))
{
if (SUCCEEDED(hr = _device->GetRenderTargetData(backBuf, _surface)))
{
if (SUCCEEDED(hr = D3DXSaveSurfaceToFileInMemory(&buf, D3DXIFF_DIB, _surface, NULL, NULL)))
{
LPVOID imgBuf = buf->GetBufferPointer();
DWORD length = buf->GetBufferSize();
在buf中,您将拥有原始图像数据。 不要忘记发布所有内容。
答案 1 :(得分:0)
请注意,EndScene会对要渲染的场景进行排队 - 您无法保证在此之前(或者甚至紧接着之后)渲染了任何内容。
IDirect3DDevice9::GetFrontBufferData可能对您有用。它“生成设备前端缓冲区的副本,并将该副本放在应用程序提供的系统内存缓冲区中。”
您要做的是调用CreateOffscreenPlainSurface在系统内存中创建pSurface,然后调用GetFrontBufferData(0,pSurface)。