I've got a 2D array of RGB values that represent a plane's painted vertices. I'd like to store the final vertex colours of the plane in a .dds file so I can load the .dds file later on as a texture.
How might I approach this?
I've got a 2D array of RGB values that represent a plane's painted vertices. I'd like to store the final vertex colours of the plane in a .dds file so I can load the .dds file later on as a texture.
How might I approach this?
Thanks to Chuck in the comments, I've found this solution works for me. There are likely improvements to be made. The approach can be broken into a few steps.
Step one is to deal with capturing the device context and D3D device to use for rendering, and setting the correct texture description to be used when creating the texture to be captured using SaveDDSTextureToFile (ScreenGrab). The below description works when each float contains four byte values for each colour and for the alpha value.
void DisplayChunk::SaveVertexColours(std::shared_ptr<DX::DeviceResources> DevResources)
{
// Setup D3DDeviceContext and D3DDevice
auto devicecontext = DevResources->GetD3DDeviceContext();
auto device = DevResources->GetD3DDevice();
// Create Texture2D and Texture2D Description
ID3D11Texture2D* terrain_texture;
D3D11_TEXTURE2D_DESC texture_desc;
// Set up a texture description
texture_desc.Width = TERRAINRESOLUTION;
texture_desc.Height = TERRAINRESOLUTION;
texture_desc.MipLevels = texture_desc.ArraySize = 1;
texture_desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
texture_desc.SampleDesc.Count = 1;
texture_desc.SampleDesc.Quality = 0;
texture_desc.Usage = D3D11_USAGE_DYNAMIC;
texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
texture_desc.MiscFlags = 0;
Step two is to create a vector of floats and populate it with the relevant RGBA values. The reason I used a vector was for convenience in terms of pushing the separate float values for R, G, B, and A each iteration. This way at each vertex position you can push back the required sixteen byte values (four from each float as discussed above).
// Create vertex colour vector
std::vector<float> colour_vector;
for (int i = 0; i < TERRAINRESOLUTION; i++) {
for (int j = 0; j < TERRAINRESOLUTION; j++) {
colour_vector.push_back((float)m_terrainGeometry[i][j].color.x);
colour_vector.push_back((float)m_terrainGeometry[i][j].color.y);
colour_vector.push_back((float)m_terrainGeometry[i][j].color.z);
colour_vector.push_back((float)m_terrainGeometry[i][j].color.w);
}
}
Step three is to fill a buffer with the vertex RGBA values. Buffer size must be equal to the total number of bytes required for storage, which is four bytes per float, four floats per vertex, and TERRAINTRESOLUTION * TERRAINTRESOLUTION vertices. Example of a 10 x 10 terrain: 4(bytes) x 4(floats) x 10(width) x 10(height) = 1600 bytes to store RGBA of each vertex.
// Initialise buffer parameters
const int components = 4;
const int length = components * TERRAINRESOLUTION * TERRAINRESOLUTION;
// Fill buffer with vertex colours
float* buffer = new float[length * sizeof(float)];
for (int i = 0; i < length; i++)
buffer[i] = colour_vector[i];
Final step is to create the texture data using the contents of the buffer created above. pSysMem required a pointer to the buffer, used as the initialisation data. SysMemPitch must be set to the size of one row. Using CreateTexture2D, a new texture can be created using the stored byte values. SaveDDSTextureToFile allows for saving the texture resource to an external .dds file. Don't forget to delete the buffer after use.
// Set the texture data using the buffer contents
D3D11_SUBRESOURCE_DATA texture_data;
texture_data.pSysMem = (void*)buffer;
texture_data.SysMemPitch = TERRAINRESOLUTION * components * sizeof(float);
// Create the texture using the terrain colour data
device->CreateTexture2D(&texture_desc, &texture_data, &terrain_texture);
// Save the texture to a .dds file
HRESULT hr = SaveDDSTextureToFile(devicecontext, terrain_texture, L"terrain_output.dds");
// Delete the buffer
delete[] buffer;
}
Some resources I used whilst implementing: