我正在尝试将 DirectX 程序的每一帧都转换为 YUV(用于视频编码)。因此,我首先需要每个帧上每个像素的 RGB(A) 值。我需要从后台缓冲区中获取这些。

因为 DirectX 中没有 glReadPixels,所以我执行以下操作:

  • 获取指向backbuffer的renderTargetView的指针并获取backbuffer资源
  • 将此资源转换为 ID3D10Texture2D
  • 制作一个暂存纹理​​,并对上一步中的 texture2D 进行 CopyResource

  • 此时我可以使用 D3DX10SaveTextureToFile 并且这个暂存纹理​​将正确地将后台缓冲区保存为图像。

    但是,我不想绕道使用磁盘,我想立即获取RGB数据,因此我执行以下操作:
  • 映射暂存资源
  • 读取映射纹理的 pData 以获得 RGB(A) 值

  • 问题:RGB 值是垃圾。这是像素 (1,1) 的示例



    这特别奇怪,因为我使用相同的代码来映​​射另一个暂存纹理​​(来自另一个屏幕外渲染目标)并且这段代码在那里工作得很好。

    这是我的代码:
    // Get resource pointer to backbuffer
    ID3D10Resource *backbufferRes;
    m_D3D->GetRenderTargetView()->GetResource(&backbufferRes);
    
    // Cast backbuffer resource to texture2D
    ID3D10Texture2D* tempTexture = 0;
    backbufferRes->QueryInterface(__uuidof(ID3D10Texture2D),(LPVOID*) &tempTexture);
    backbufferRes->Release();
    
    // Get the descriptor of this texture2D
    D3D10_TEXTURE2D_DESC descDefault;
    tempTexture->GetDesc(&descDefault);
    
    // Create a staging texture desc based on the texture of the backbuffer
    D3D10_TEXTURE2D_DESC descStaging;
    descStaging = descDefault;
    descStaging.Usage = D3D10_USAGE_STAGING;
    descStaging.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
    descStaging.BindFlags = 0;
    
    // Create the new empty staging texture
    ID3D10Texture2D *texture = 0;
    m_D3D->GetDevice()->CreateTexture2D( &descStaging, NULL, &texture);
    
    // Copy the backbuffer texture data (tempTexture) to the staging texture (texture)
    m_D3D->GetDevice()->CopyResource(texture, tempTexture);
    
    // This call works perfectly, image is correct!
    // D3DX10SaveTextureToFile(texture, D3DX10_IFF_BMP, L"D:\\img.bmp");
    
    // We want to avoid disk access, so instead let's map the texture and read its RGB data
    D3D10_MAPPED_TEXTURE2D mappedTexture;
    hr = texture->Map(D3D10CalcSubresource(0, 0, 1), D3D10_MAP_READ, 0, &mappedTexture);
    FLOAT* m_pBits = (FLOAT*) malloc(4 * descStaging.Width * descStaging.Height * sizeof(FLOAT));
    if(!FAILED(hr)) {
        memcpy(m_pBits, mappedTexture.pData, 4 * descStaging.Width * descStaging.Height);
        texture->Unmap(D3D10CalcSubresource(0, 0, 1));
    }
    texture->Release();
    tempTexture->Release();
    
    fp = fopen("D:\\output.txt", "a");
    for( UINT row = 0; row < descStaging.Height; row++ )
    {
        UINT rowStart = row * mappedTexture.RowPitch / 4;
        for( UINT col = 0; col < descStaging.Width; col++ )
        {
            r = m_pBits[rowStart + col*4 + 0]; // Red (X)
            g = m_pBits[rowStart + col*4 + 1]; // Green (Y)
            b = m_pBits[rowStart + col*4 + 2]; // Blue (Z)
            a = m_pBits[rowStart + col*4 + 3]; // Alpha (W)
    
            // Save pixel values to disk
            fprintf(fp, "%d %d - %f %f %f\n",  col + 1, row + 1, r, g, b);
        }
    }
    fclose(fp);
    

    有没有人知道问题可能是什么?
    非常感谢所有帮助。

    最佳答案

    老问题,但我认为这可能是问题所在:

    使用 texture->Map() 映射纹理后,您尝试一次性将其复制到 m_pBits 中。除非映射纹理的 RowPitch 与其宽度相同(参见 here ),否则这将不起作用。

    相反,您必须逐行复制图像:

    BYTE* source = static_cast<BYTE*>(mappedTexture.pData);
    BYTE& dest = m_pBits;
    for (int i = 0; i < IMAGE_HEIGHT; ++i) {
        memcpy(dest, source, IMAGE_WIDTH * 4); // for 4 bytes per pixel
        source += mappedTexture.RowPitch;
        dest += IMAGE_WIDTH * 4;
    }
    

    关于DirectX 将后台缓冲区数据写入文件,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15324627/

    10-15 04:16