我已经将场景渲染为纹理(RTT,渲染为纹理)。在此过程中,渲染目标为prtv [ID3DRenderTargetView *],相应的纹理为ptextureRTV [ID3D11Resource *]。
现在,我想从鼠标所在的位置读取一个像素并发现错误。为了弄清楚错误的出处,我转向打印出纹理以查看其含义。
我创建D3D11_USAGE_STAGING资源ptextureStaging [ID3D11Resource *]并将ptextureRTV复制到ptextureStaging。然后,我映射ptextureStaing,使用其数据创建.ppm图像并取消映射。但是,该图像不是我想要的图像。
我也尝试使用SaveDDSTextureToFile将纹理存储到.dds图像中。它真的很好。
这是我的代码:
创建DDS图像(通过并更正):
DirectX::SaveDDSTextureToFile(pdx11_unit->pdevCon.Get(), ptextureRTV.Get(), L"Image/image.dds");
复制并映射:
RenderToTexture();//prepare texture
pdx11_unit->pdevCon->CopyResource(ptextureStaging.Get(), ptextureRTV.Get());//copy data to staing texutre
D3D11_MAPPED_SUBRESOURCE mappedResource;
ZeroMemory(&mappedResource, sizeof(D3D11_MAPPED_SUBRESOURCE));
pdx11_unit->pdevCon->Map(ptextureStaging.Get(), 0, D3D11_MAP_READ, 0, &mappedResource);//map to cpu memory
_pixel *pdata = (_pixel*)mappedResource.pData;
//create .ppm image
ofstream image("Image/image.ppm", ios::out | ios::binary | ios::trunc);
image << "P3\n" << Win32Unit::realWidth << " " << Win32Unit::realHeight << "\n255\n";
for (int i = Win32Unit::realHeight - 1; i >= 0; i--)
{
for (int j = 0; j < Win32Unit::realWidth; j++) {
int ir = pdata[i*Win32Unit::realWidth + j].r;
int ig = pdata[i*Win32Unit::realWidth + j].g;
int ib = pdata[i*Win32Unit::realWidth + j].b;
image << ir << ' ' << ig << ' ' << ib << '\n';
}
}
pdx11_unit->pdevCon->Unmap(ptextureStaging.Get(), 0);
我已经找到原因了。如果我现在具有大小为784x561的纹理并且想要读取(i,j)处的像素,则查询((_pixel *)mappedResource.pdata)[i * 784 + j]是错误的,因为被映射的资源的width = 800其实。此宽度等于mappingResouce.RowPitch / sizeof(_pixel)。因此,要将像素加载到CPU内存中,正确的代码是:
int slicePitch = Win32Unit::realHeight*Win32Unit::realWidth;
int rowCount = Win32Unit::realHeight;
int rowPitch = Win32Unit::realWidth;
std::unique_ptr<_pixel[]> pixels(new (std::nothrow) _pixel[slicePitch]);
_pixel* dptr = pixels.get();
_pixel* sptr = (_pixel*)mappedResource.pData;
for (int i = 0; i < rowCount; i++) {
memcpy_s(dptr, rowPitch * sizeof(_pixel), sptr, rowPitch * sizeof(_pixel));
dptr += rowPitch;
sptr += mappedResource.RowPitch / sizeof(_pixel);
}