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 格式或其他分隔符。
相关推荐
棒棒的皮皮1 天前
【Python】Open3d用于3D测高项目
python·3d·open3d
CV实验室2 天前
CV论文速递:覆盖视频生成与理解、3D视觉与运动迁移、多模态与跨模态智能、专用场景视觉技术等方向 (11.17-11.21)
人工智能·计算机视觉·3d·论文·音视频·视频生成
Highcharts.js3 天前
使用 Highcharts 3D图表入门
3d·highcharts·使用文档·3d图表·交互图表·三维图表·3d 可视化
O***p6043 天前
C++在游戏中的Ogre3D
游戏·3d·ogre
sdjnled2293 天前
山东裸眼3D立体LED显示屏专业服务商
人工智能·3d
徒慕风流3 天前
GeoSight:基于 Open3D 与 PySide6 的参数化 3D 模型处理与实时点云监控工具
计算机视觉·3d·信号处理
三条猫4 天前
将3D CAD 模型结构树转换为图结构,用于训练CAD AI的思路
人工智能·3d·ai·cad·模型训练·图结构·结构树
二川bro4 天前
第59节:常见问题汇编 - 60个典型问题解答
javascript·3d·threejs
zhangfeng11335 天前
aigc 从2d 到 3d的形式转变,李飞飞在介绍WorldLabs的Marble平台,会围绕“空间智能“的核心理念,自动驾驶就是2d形式
3d·自动驾驶·aigc
da_vinci_x6 天前
PS 3D Viewer (Beta):概念美术的降维打击,白模直接在PS里转光打影出5张大片
人工智能·游戏·3d·prompt·aigc·材质·游戏美术