Direct3D生成的DDS文件纹理数据还原

在图形编程和图像处理领域,DDS(DirectDraw Surface)文件格式广泛用于存储纹理数据。由于DDS文件通常包含压缩或浮点格式的纹理数据,因此,有时我们需要将DDS文件中的纹理数据还原为易于分析和处理的文本格式。本文将详细介绍如何使用Direct3D(D3D9)库,读取DDS文件中的纹理数据并将其保存为TXT文件,以便于进一步分析。

1. 为什么需要将DDS文件数据还原为TXT格式?

DDS文件在图形应用中常用于高效存储纹理数据,但它们通常是二进制格式,直接读取不太方便。将纹理数据转换为文本格式有助于:

  • 数据分析:方便开发人员分析每个像素的具体颜色值和纹理特性。
  • 调试和验证:在调试过程中,文本格式比二进制格式更直观,有助于验证纹理是否正确加载和处理。
  • 跨平台应用:文本文件更易于在不同平台之间传输和查看。

2. 示例:将DDS纹理数据还原为TXT格式

接下来,我们通过一个示例代码,演示如何将从DDS文件加载的纹理数据保存为TXT格式的文件。

cpp 复制代码
#include <iostream>
#include <fstream>
#include <d3d9.h>
#include <d3dx9.h>
#include <cassert>

#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")

LPDIRECT3D9             m_pD3D = NULL;
LPDIRECT3DDEVICE9       m_pD3DDev = NULL;
LPDIRECT3DTEXTURE9      m_pTexture = NULL;
int                     m_nWidth = 0;
int                     m_nHeight = 0;

#define SafeRelease(p) if (p != NULL) { p->Release(); p = NULL; }

HRESULT InitD3D(HWND hwnd) {
    if ((m_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
    {
        return E_FAIL;
    }

    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
    d3dpp.BackBufferWidth = m_nWidth;
    d3dpp.BackBufferHeight = m_nHeight;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

    if (FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
        D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &m_pD3DDev)))
    {
        if (FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
            D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &m_pD3DDev)))
        {
            return E_FAIL;
        }
    }
    return S_OK;
}

HRESULT LoadDDSTexture(const char* path) {
    HRESULT hr;
    hr = D3DXCreateTextureFromFile(m_pD3DDev, path, &m_pTexture);
    if (FAILED(hr)) {
        std::cout << "Failed to load DDS texture!" << std::endl;
        return hr;
    }

    // Get the texture's dimensions
    D3DSURFACE_DESC desc;
    m_pTexture->GetLevelDesc(0, &desc);
    m_nWidth = desc.Width;
    m_nHeight = desc.Height;

    return S_OK;
}

HRESULT SaveTextureToTXT(const char* path) {
    if (m_pTexture == NULL) {
        std::cout << "No texture to save!" << std::endl;
        return E_FAIL;
    }

    // Get the texture's surface level
    LPDIRECT3DSURFACE9 pSurface;
    HRESULT hr = m_pTexture->GetSurfaceLevel(0, &pSurface);
    if (FAILED(hr)) {
        std::cout << "Failed to get surface level!" << std::endl;
        return hr;
    }

    // Lock the surface to access pixel data
    D3DLOCKED_RECT lockedRect;
    hr = pSurface->LockRect(&lockedRect, NULL, D3DLOCK_READONLY);
    if (FAILED(hr)) {
        std::cout << "Failed to lock surface!" << std::endl;
        return hr;
    }

    // Open the output text file
    std::ofstream outFile(path);
    if (!outFile.is_open()) {
        std::cout << "Failed to open output file!" << std::endl;
        return E_FAIL;
    }

    // Write the texture data to the text file
    for (int y = 0; y < m_nHeight; ++y) {
        for (int x = 0; x < m_nWidth; ++x) {
            // Get the pixel data (assuming RGBA format with 32-bit floating point per channel)
            DWORD* pixel = (DWORD*)((BYTE*)lockedRect.pBits + y * lockedRect.Pitch + x * sizeof(DWORD));
            float* data = (float*)pixel;

            // Write RGBA data (assuming D3DFMT_A32B32G32R32F format)
            outFile << data[0] << " " << data[1] << " " << data[2] << " " << data[3] << std::endl;
        }
    }

    // Close the file
    outFile.close();

    // Unlock the surface
    pSurface->UnlockRect();

    // Release the surface
    SafeRelease(pSurface);

    return S_OK;
}

int main() {
    // Initialize Direct3D
    HWND hwnd = GetConsoleWindow();  // Use console window for D3D initialization
    if (FAILED(InitD3D(hwnd))) {
        std::cout << "Direct3D Initialization Failed!" << std::endl;
        return -1;
    }

    // Load the DDS texture file
    const char* ddsFilePath = "input.dds";
    if (FAILED(LoadDDSTexture(ddsFilePath))) {
        std::cout << "Failed to load DDS file!" << std::endl;
        return -1;
    }

    // Save the texture data to a TXT file
    const char* txtFilePath = "output.txt";
    if (FAILED(SaveTextureToTXT(txtFilePath))) {
        std::cout << "Failed to save texture to TXT!" << std::endl;
        return -1;
    }

    std::cout << "DDS texture data successfully saved to " << txtFilePath << std::endl;

    // Cleanup
    SafeRelease(m_pD3DDev);
    SafeRelease(m_pD3D);

    return 0;
}

3. 代码解析

初始化 Direct3D (InitD3D)

  • 使用 Direct3DCreate9 初始化 Direct3D 实例,并创建一个 Direct3D 设备(m_pD3DDev),这是后续操作的基础。

加载 DDS 文件 (LoadDDSTexture)

  • 使用 D3DXCreateTextureFromFile 从指定路径加载 DDS 文件,并获取纹理的宽度和高度。m_pTexture 保存加载的纹理对象。

保存纹理数据到 TXT 文件 (SaveTextureToTXT)

  • 获取纹理的表面级别,并锁定该表面以便读取像素数据。
  • 假设纹理采用 32 位浮点 RGBA 格式(D3DFMT_A32B32G32R32F),从每个像素的内存中提取 RGBA 值。
  • 将每个像素的 RGBA 值保存到文本文件,每行一个像素的 4 个浮点数值,空格分隔。

主程序 (main)

  • 调用 Direct3D 初始化函数,加载 DDS 文件并将纹理数据保存为 TXT 文件。

4. 结果示例

假设纹理数据是浮点格式存储的,每个像素的 RGBA 值将被转换为以下格式存储:

python 复制代码
0.1234 0.2345 0.3456 0.4567 0.5678 0.6789 0.7890 0.8901 ...

5. 注意事项

  • 纹理格式 :此代码假设 DDS 文件使用的是 D3DFMT_A32B32G32R32F 格式,若 DDS 文件使用其他格式(如 D3DFMT_R8G8B8A8),则需要调整代码来处理不同的像素格式。
  • 内存锁定 :锁定纹理表面时要小心,避免内存泄漏。使用 UnlockRect 来解锁内存。
  • 输出文件格式:您可以根据需要调整输出格式,例如使用 CSV 格式或其他分隔符。
相关推荐
199795014329 小时前
2D/3D 数码视频显微镜
大数据·测试工具·3d·自动化·视觉检测·制造
Vec[95]10 小时前
光照贴图原理
c++·3d·贴图
GIS瞧葩菜13 小时前
对载入的3dtiles进行旋转、平移和缩放变换。
3d·cesium
zhang988000015 小时前
李飞飞的wordlabs一张图片可以生成3D视频的原理是什么?想入行AI的学生必学的技术!
人工智能·3d·音视频
GIS瞧葩菜1 天前
3dtile平移子模型以及修改 3D Tiles 模型的模型矩阵z平移
3d·矩阵·cesium
极地星光1 天前
探索3D世界:使用 lib3ds 读取和解析 3DS 文件
3d
CV万花筒1 天前
点云3DHarris角点检测算法推导
算法·3d
二狗子的翠花1 天前
3d/伪3d统计图形
android·服务器·3d
cnbestec2 天前
XELA - uSkin 三轴触觉传感器:为机器人赋予敏锐触感
人工智能·3d·机器人