我想创建一个函数将输入的dds文件转换为另一种格式(也是DDS) 函数签名会像这样
std::vector<byte> ConvertDDS(const byte* src, const size_t src_len, const DXGI_FORMAT format)
在这里
src
将是指向 dds 文件内容的指针 (full dds),而 format
将是我们要将 src
转换成的格式,该函数返回一个字节向量,其中包含转换后的 dds.这是我当前代码的一个工作示例
#include <iostream>
#include <fstream>
#include <vector>
#include <DirectXTex.h>
void throw_error(std::string err, HRESULT hr)
{
LPWSTR errorText = nullptr;
DWORD messageLength = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, hr & 0x0000FFFF, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&errorText, 0, nullptr);
if (messageLength > 0)
{
std::wstring wErrorText(errorText);
std::string errorString(wErrorText.begin(), wErrorText.end());
LocalFree(errorText);
throw std::invalid_argument(err + ": " + errorString);
}
}
std::vector<byte> ConvertDDS(const byte* src, const size_t src_len, const DXGI_FORMAT format)
{
DirectX::TEX_FILTER_FLAGS dwFilter = DirectX::TEX_FILTER_DEFAULT;
DirectX::TEX_FILTER_FLAGS dwSRGB = DirectX::TEX_FILTER_DEFAULT;
DirectX::TEX_FILTER_FLAGS dwConvert = DirectX::TEX_FILTER_DEFAULT;
DirectX::TEX_FILTER_FLAGS dwFilterOpts = DirectX::TEX_FILTER_DEFAULT;
DirectX::TexMetadata meta;
// Initialize COM (needed for WIC)
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (FAILED(hr))
throw_error("Failed to initialize COM", hr);
std::unique_ptr<DirectX::ScratchImage> image(new (std::nothrow) DirectX::ScratchImage);
// load texture from memory, supported types are DDS, PNG and TGA
hr = DirectX::LoadFromDDSMemory(src, src_len, DirectX::DDS_FLAGS_ALLOW_LARGE_FILES, &meta, *image);
if (FAILED(hr))
throw_error("Can't load texture from memory", hr);
// If format doesn't match convert it
if (meta.format != format)
{
// --- Planar ------------------------------------------------------------------
if (DirectX::IsPlanar(meta.format))
{
auto img = image->GetImage(0, 0, 0);
assert(img);
const size_t nimg = image->GetImageCount();
std::unique_ptr<DirectX::ScratchImage> timage(new (std::nothrow) DirectX::ScratchImage);
hr = ConvertToSinglePlane(img, nimg, meta, *timage);
if (FAILED(hr))
throw_error(" FAILED [converttosingleplane]", hr);
auto& tinfo = timage->GetMetadata();
meta.format = tinfo.format;
assert(meta.width == tinfo.width);
assert(meta.height == tinfo.height);
assert(meta.depth == tinfo.depth);
assert(meta.arraySize == tinfo.arraySize);
assert(meta.mipLevels == tinfo.mipLevels);
assert(meta.miscFlags == tinfo.miscFlags);
assert(meta.dimension == tinfo.dimension);
image.swap(timage);
}
// --- Decompress --------------------------------------------------------------
if (DirectX::IsCompressed(meta.format))
{
std::unique_ptr<DirectX::ScratchImage> nimage(new (std::nothrow) DirectX::ScratchImage);
hr = DirectX::Decompress(
image->GetImages(),
image->GetImageCount(),
meta,
DXGI_FORMAT_UNKNOWN,
*nimage
);
if (FAILED(hr))
throw_error("Can't decompress dds texture", hr); // decompress new texture failed
meta.format = nimage->GetMetadata().format;
image.swap(nimage);
}
if (meta.format != format)
{
// If the original file is compressed we compress the src
// Else we just convert it
if (DirectX::IsCompressed(format))
{
std::unique_ptr<DirectX::ScratchImage> nimage(new (std::nothrow) DirectX::ScratchImage);
hr = DirectX::Compress(
image->GetImages(),
image->GetImageCount(),
meta,
format,
DirectX::TEX_COMPRESS_FLAGS::TEX_COMPRESS_DEFAULT,
DirectX::TEX_THRESHOLD_DEFAULT,
*nimage
);
if (FAILED(hr))
throw_error("Can't compress dds texture", hr); // convert new texture failed
image.swap(nimage);
}
else
{
std::unique_ptr<DirectX::ScratchImage> nimage(new (std::nothrow) DirectX::ScratchImage);
hr = DirectX::Convert(
image->GetImages(),
image->GetImageCount(),
meta,
format,
dwFilter | dwFilterOpts | dwSRGB | dwConvert,
DirectX::TEX_THRESHOLD_DEFAULT,
*nimage
);
if (FAILED(hr))
throw_error("Can't convert dds texture", hr); // convert new texture failed
image.swap(nimage);
}
meta.format = image->GetMetadata().format;
}
}
std::unique_ptr<DirectX::Blob> blob(new (std::nothrow) DirectX::Blob);
DirectX::SaveToDDSMemory(
image->GetImages(),
image->GetImageCount(),
image->GetMetadata(),
DirectX::DDS_FLAGS_NONE,
*blob.get()
);
std::vector<byte> result(blob->GetBufferSize());
std::memcpy(result.data(), blob->GetBufferPointer(), blob->GetBufferSize());
return result;
}
此代码似乎有效,但如我所说,输出没有 transparent 背景,整体看起来不对......我该怎么办?我对 DirectXTex API 不是很熟悉,所以如果有人能帮助我,我会很高兴。
我尝试将格式为
DXGI_FORMAT_B8G8R8A8_UNORM
的 DDS 纹理转换为 DXGI_FORMAT_R8_UNORM
但失败了。从
DXGI_FORMAT_B8G8R8A8_UNORM
到DXGI_FORMAT_R8_UNORM
你想要什么行为?
RGB 到 R 转换的默认行为是使用亮度将 RGB 转换为灰度并将其存储在 RED 通道中。没有地方可以在目标中放置透明通道。
您是否希望 alpha 通道在这里“屏蔽”图像?如果是这样,“背景颜色”是什么?
如果你想保留 alpha 通道,你需要使用
DXGI_FORMAT_R8A8_UNORM
.
DirectXTex 支持其他映射通道的方式。您可以进行频道调配,也可以使用
、TEX_FILTER_RGB_COPY_RED
或TEX_FILTER_RGB_COPY_GREEN
等标志。请参见过滤标志。TEX_FILTER_RGB_COPY_BLUE