feat: DDS 纹理加载器(BC 压缩直传 + mip 链,参考 Horizon 实现)
- Assets::Dds 解析器:中性 DdsFormat 枚举(Assets 层禁 Vulkan 头铁律), 支持 legacy fourcc(DXT1/3/5/ATI1/2)+ DX10 头(BC1..BC7/RGBA8/BGRA8) + 未压缩 32bpp + 2D mip 链;数据不解码,直接上传由硬件采样解码 - Texture:按扩展名分发(.dds → InitFromDds);渲染侧负责格式映射与 sRGB 语义(颜色图走 SRGB 变体,BC4/5/6H 数据图保持线性);view/sampler 覆盖完整 mip 链;逐 mip copyBufferToImage(紧凑排布) - Model::GetOrLoadTexture:FBX/DCC 路径反斜杠归一化(否则 Linux 全挂) - DescriptorManager 池 1000 → 4096(SunTemple 1056 材质集打爆过; 材质去重属材质系统任务) - main.cpp 临时挂 SunTemple 场景验证:48 张 DDS 全部加载(2048²、12 mips), 1056 mesh 渲染正常,validation 零警告
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/23.
|
||||
//
|
||||
// DDS 文件解析(最小实现,不解码压缩块)。
|
||||
//
|
||||
// 设计:GPU 原生支持 BC 压缩格式——DDS 的压缩数据**直接上传**为
|
||||
// BC1/BC2/BC3/BC4/BC5/BC6H/BC7 纹理由硬件采样解码,不做 CPU 解码。
|
||||
// 输出中性 DdsFormat(本层禁 Vulkan 头),vk::Format 映射与 sRGB
|
||||
// 语义由调用方(Texture,渲染侧)决定。
|
||||
//
|
||||
// 支持:
|
||||
// - legacy fourcc:DXT1/DXT3/DXT5/ATI1/BC4U/ATI2/BC5U
|
||||
// - DX10 扩展头:BC1..BC7、R8G8B8A8、B8G8R8A8
|
||||
// - 未压缩 32bpp(DDPF_RGB | DDPF_ALPHAPIXELS)
|
||||
// - 2D + mip 链(cubemap 面标志暂不支持,报错)
|
||||
//
|
||||
// 输出:Mips[r] = 第 r 级完整数据(BC 按块行紧凑排布:
|
||||
// bytes = ceil(w/4)*ceil(h/4)*blockBytes)。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_DDSLOADER_H
|
||||
#define HELLOVULKAN_DDSLOADER_H
|
||||
|
||||
#include <Engine/Core/Types.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Engine::Assets::Dds {
|
||||
|
||||
// 中性格式(Assets 层不感知 Vulkan;映射在渲染侧 Texture)
|
||||
enum class DdsFormat {
|
||||
BC1, BC2, BC3, BC4, BC5, BC6H, BC7,
|
||||
RGBA8,
|
||||
BGRA8, // 按字节序上传后视作 RGBA(近似,触发警告)
|
||||
};
|
||||
|
||||
struct DdsData {
|
||||
u32 Width = 0;
|
||||
u32 Height = 0;
|
||||
u32 MipLevels = 1;
|
||||
DdsFormat Format = DdsFormat::RGBA8;
|
||||
std::vector<std::vector<u8>> Mips; // 每级完整数据(紧凑排布)
|
||||
bool BlockCompressed = false; // BC 格式(rowPitch 按块计算)
|
||||
};
|
||||
|
||||
// 解析 DDS 文件;失败返回 false 并写 errMsg
|
||||
bool Load(const std::string& path, DdsData& out, std::string& errMsg);
|
||||
|
||||
// 指定 mip 级的单行字节跨度(BC = 块行;RGBA8 = w*4)
|
||||
u32 RowPitch(const DdsData& data, u32 mipLevel);
|
||||
|
||||
} // namespace Engine::Assets::Dds
|
||||
|
||||
#endif //HELLOVULKAN_DDSLOADER_H
|
||||
@@ -50,12 +50,12 @@ namespace Engine::ECS {
|
||||
// 分量 → world 矩阵(T * R * S)
|
||||
TransformComponent& Compose()
|
||||
{
|
||||
glm::mat4 t = glm::translate(glm::mat4(1.0f), position);
|
||||
glm::mat4 r =
|
||||
const glm::mat4 t = glm::translate(glm::mat4(1.0f), position);
|
||||
const glm::mat4 r =
|
||||
glm::rotate(glm::mat4(1.0f), glm::radians(rotation.y), glm::vec3(0, 1, 0)) *
|
||||
glm::rotate(glm::mat4(1.0f), glm::radians(rotation.x), glm::vec3(1, 0, 0)) *
|
||||
glm::rotate(glm::mat4(1.0f), glm::radians(rotation.z), glm::vec3(0, 0, 1));
|
||||
glm::mat4 s = glm::scale(glm::mat4(1.0f), scale);
|
||||
const glm::mat4 s = glm::scale(glm::mat4(1.0f), scale);
|
||||
world = t * r * s;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,10 @@ namespace Engine {
|
||||
Device& m_Device;
|
||||
vk::DescriptorPool m_Pool;
|
||||
|
||||
static constexpr u32 kMaxSets = 1000;
|
||||
// 描述符池容量:需 ≥ 场景全部材质集合数 + 每帧集合。
|
||||
// SunTemple(984 mesh 材质)把 1000 打爆过;材质去重(同贴图共享
|
||||
// Material)属于材质系统任务,在那之前留足余量
|
||||
static constexpr u32 kMaxSets = 4096;
|
||||
};
|
||||
|
||||
} // namespace Engine
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Engine {
|
||||
|
||||
class Texture {
|
||||
public:
|
||||
// 从磁盘图片加载
|
||||
// 从磁盘图片加载(按扩展名分发:.dds → DdsLoader,其它 → stbi)
|
||||
Texture(Device& device, MemoryAllocator& allocator, const std::string& path);
|
||||
|
||||
// 程序化纹理:纯色(1x1),用于地面/调试等不依赖磁盘资产的场景
|
||||
@@ -38,6 +38,8 @@ namespace Engine {
|
||||
vk::ImageView GetView() const { return m_View; }
|
||||
u32 GetWidth() const { return m_Width; }
|
||||
u32 GetHeight() const { return m_Height; }
|
||||
vk::Format GetFormat() const { return m_Format; }
|
||||
u32 GetMipLevels() const { return m_MipLevels; }
|
||||
|
||||
vk::Sampler GetSampler() const { return m_Sampler; }
|
||||
|
||||
@@ -46,13 +48,19 @@ namespace Engine {
|
||||
Texture(Device& device, MemoryAllocator& allocator, ProceduralTag,
|
||||
const std::array<u8, 4>& rgba);
|
||||
|
||||
// 公共路径:staging → device local image → view/sampler
|
||||
// 公共路径:staging → device local image → view/sampler(RGBA8 单 mip)
|
||||
void InitFromPixels(const void* pixels, u32 width, u32 height);
|
||||
|
||||
// DDS 路径:压缩数据直传(BC 硬件采样解码)+ 文件自带 mip 链
|
||||
void InitFromDds(const std::string& path);
|
||||
|
||||
Device& m_Device;
|
||||
vk::Image m_Image;
|
||||
vk::ImageView m_View;
|
||||
|
||||
vk::Format m_Format = vk::Format::eUndefined;
|
||||
u32 m_MipLevels = 1;
|
||||
|
||||
vk::Sampler m_Sampler;
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user