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 格式或其他分隔符。
相关推荐
Tian_Hang1 天前
eclipse ditto 学习笔记
运维·服务器·开发语言·javascript·3d
AI视觉网奇1 天前
BambuStudio 编译实战 2026
3d
AI前沿资讯1 天前
AI3D角色生产如何减少返工?用 V2Fun 前移建模与动画流程
人工智能·3d
蓝速科技1 天前
蓝速科技视觉 3D 全息舱 AI 数字人一体机带灯与无灯款深度评测
人工智能·科技·3d
尘中远1 天前
【Qwt 7.0 系列】3D 数据可视化 —— OpenGL 高性能三维绘图
qt·3d·qcustomplot·qwt·科学绘图·高性能绘图
林恒smileZAZ2 天前
Three.js 3D 地图特效与材质实现指南
javascript·3d·材质
蓝速科技2 天前
蓝速科技 3D 全息舱 AI 数字人博物馆导览效果实录
人工智能·科技·3d
lauo2 天前
【案例】每天省5小时:ibbot手机文章中心-采集到自动发布-工作流(agent)
人工智能·microsoft·3d·智能手机
chaoyuanl2 天前
沉浸式飞行影院进场安装前期筹备事项
大数据·科技·3d·xr·娱乐
探物 AI19 天前
【3D·感知】从PointNet到PointPillars:如何让自动驾驶汽车“实时“看见3D世界?
3d·自动驾驶·汽车