首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Direct3D9 BackBuffer to PixelArray

Direct3D9 BackBuffer to PixelArray
EN

Stack Overflow用户
提问于 2013-12-19 02:09:53
回答 2查看 1.1K关注 0票数 0

我在试着玩DirectX游戏。我成功地加载了我的钩子,并且能够使用以下方法将映像/后台缓冲区保存到磁盘上:

代码语言:javascript
复制
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;
}

它成功地拯救了我们,我很高兴。但是,我希望保存到像素数组,而不是磁盘。我试着用:

代码语言:javascript
复制
#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。

编辑:我试过:

代码语言:javascript
复制
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();
}

但我的形象是黑色的。有什么想法吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-12-19 02:37:14

请注意,EndScene排队等待呈现的场景--不能保证在此之前(甚至是之后)已经呈现了任何内容。

IDirect3DDevice9:GetFrontBufferData可能对你更有用。它“生成设备前端缓冲区的副本,并将该副本放置在应用程序提供的系统内存缓冲区中。

您要做的是调用CreateOffscreenPlainSurface在系统内存中创建pSurface,然后调用GetFrontBufferData(0,pSurface)。

票数 0
EN

Stack Overflow用户

发布于 2016-03-04 00:42:20

有点晚了。但希望这对某人有帮助。

创建

代码语言:javascript
复制
        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)))

俘获

代码语言:javascript
复制
    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
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20672234

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档