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 格式或其他分隔符。
相关推荐
Hali_Botebie1 小时前
【蒸馏(1)】UniDistill:用于BEV 3D检测的通用跨模态蒸馏框架!
3d
MediaTea2 小时前
Ae 效果详解:3D 通道提取
3d
3DVisionary2 小时前
XTOP3D的DIC技术在极端条件下的应用解决方案
数码相机·3d·航空工业·全场应变测量·航空机匣内部四测头同步测量·反射镜辅助dic观测·四测头方案
吃个糖糖5 小时前
Halcon 3D加快表面匹配速度
3d
mirrornan21 小时前
3D全景沉浸式看车:虚拟现实重构汽车消费新体验
科技·3d·汽车·vr·3d数字化·3d看车
pixle02 天前
Three.js 快速入门教程【一】开启你的 3D Web 开发之旅
前端·javascript·3d
视觉人机器视觉2 天前
机器视觉中的3D高反光工件检测
人工智能·3d·c#·视觉检测
mirrornan2 天前
从建模到展示,如何实现3D在线预览展示?
3d
3D小将2 天前
STL 在线转 3MF,开启 3D 模型转换新体验
3d·3d格式转换
视觉人机器视觉2 天前
3D与2D机器视觉机械臂引导的区别
人工智能·数码相机·计算机视觉·3d·视觉检测