MeshFactory:程序化几何单一源 + CreatePrimitive 链路

新增 MeshFactory(Cube/Plane/Sphere/Cylinder/Cone/Torus + 切线计算),
Model 程序化几何改走 MeshFactory(收敛为单一几何源,消除重复的顶点
生成),并新增 CreatePrimitive;打通 AssetManager/IAssetUploader/
VulkanAssetUploader 的 CreatePrimitive 链路;编辑器 Procedural 弹窗
下拉 + ResolveProcedural 伪路径反解 + 场景序列化(程序化图元可存取)。
This commit is contained in:
2026-10-18 17:09:25 +08:00
parent 22309d24f0
commit f107854236
11 changed files with 654 additions and 117 deletions
+39 -91
View File
@@ -805,8 +805,8 @@ void Model::InitDefaultTextures()
Model::Model(Device& device, MemoryAllocator& allocator,
DescriptorManager& descriptorManager,
vk::DescriptorSetLayout textureLayout,
ProceduralTag, f32 halfSize, const std::array<u8, 4>& rgba,
bool transparent)
ProceduralTag, MeshData&& geo, const std::array<u8, 4>& rgba,
bool transparent, const std::string& name)
: m_Device(device)
, m_Allocator(allocator)
, m_DescriptorManager(descriptorManager)
@@ -825,16 +825,9 @@ Model::Model(Device& device, MemoryAllocator& allocator,
std::to_string(rgba[3]);
m_TextureCache.emplace(texKey, std::move(tex));
// XZ 平面,法线 +Y,从上往下看 CCW 绕序
const f32 h = halfSize;
std::vector<Vertex> vertices = {
{{-h, 0.0f, -h}, {0, 1, 0}, {0.0f, 0.0f}},
{{-h, 0.0f, h}, {0, 1, 0}, {0.0f, 0.0f}},
{{ h, 0.0f, h}, {0, 1, 0}, {0.0f, 0.0f}},
{{ h, 0.0f, -h}, {0, 1, 0}, {0.0f, 0.0f}},
};
const std::vector<u32> indices = {0, 1, 2, 0, 2, 3};
const std::vector<std::vector<u32>> lodIndices = {indices};
// 几何(顶点/索引 + 逐顶点切线)由 MeshFactory 产出:单一几何源,
// 各具名工厂不再各自内联一套立方体/平面
const std::vector<std::vector<u32>> lodIndices = {std::move(geo.indices)};
// 材质/纹理生命周期随模型(缓存持有);颜色纹理必须显式覆盖 albedo
// 槽——缺了会折到默认白纹理(白板叠白地 → 平面“消失”的教训)
@@ -845,11 +838,9 @@ Model::Model(Device& device, MemoryAllocator& allocator,
overrides);
m_Meshes.push_back(CreateScope<Mesh>(
m_Device, m_Allocator, vertices, lodIndices, mat));
// 程序化平面同样登记内建材质快照(与 m_Meshes 下标对齐,
// 编辑器材质槽 UI 不越界)
m_MeshMaterialInfos.push_back(
{"Plane", {}, MaterialParams{}, transparent});
m_Device, m_Allocator, geo.vertices, lodIndices, mat));
// 内建材质快照(与 m_Meshes 下标对齐,编辑器材质槽 UI 不越界)
m_MeshMaterialInfos.push_back({name, {}, MaterialParams{}, transparent});
RebuildUnionBounds();
}
@@ -860,8 +851,9 @@ Scope<Model> Model::CreatePlane(Device& device, MemoryAllocator& allocator,
{
return Scope<Model>(new Model(device, allocator, descriptorManager,
textureLayout, ProceduralTag{},
halfSize, std::array<u8, 4>{r, g, b, 255},
false));
MeshFactory::Plane(halfSize),
std::array<u8, 4>{r, g, b, 255}, false,
"Plane"));
}
Scope<Model> Model::CreateTransparentPlane(
@@ -872,8 +864,9 @@ Scope<Model> Model::CreateTransparentPlane(
{
return Scope<Model>(new Model(device, allocator, descriptorManager,
textureLayout, ProceduralTag{},
halfSize, std::array<u8, 4>{r, g, b, a},
true));
MeshFactory::Plane(halfSize),
std::array<u8, 4>{r, g, b, a}, true,
"Plane"));
}
Scope<Model> Model::CreateCube(Device& device, MemoryAllocator& allocator,
@@ -882,81 +875,36 @@ Scope<Model> Model::CreateCube(Device& device, MemoryAllocator& allocator,
f32 halfSize, u8 r, u8 g, u8 b)
{
return Scope<Model>(new Model(device, allocator, descriptorManager,
textureLayout, CubeTag{},
halfSize, std::array<u8, 4>{r, g, b, 255}));
textureLayout, ProceduralTag{},
MeshFactory::Cube(halfSize),
std::array<u8, 4>{r, g, b, 255}, false,
"Cube"));
}
// 程序化立方体:6 面 24 顶点(面法线朝外,CCW 从外看),36 索引。
// 结构镜像平面 ctor:默认纹理 → 纯色 albedo 覆盖 → 单 mesh
Model::Model(Device& device, MemoryAllocator& allocator,
DescriptorManager& descriptorManager,
vk::DescriptorSetLayout textureLayout,
CubeTag, f32 halfSize, const std::array<u8, 4>& rgba)
: m_Device(device)
, m_Allocator(allocator)
, m_DescriptorManager(descriptorManager)
, m_TextureLayout(textureLayout)
// 通用程序化图元:形状名 → MeshFactory 几何。非法形状名/空几何返回
// nullptr(调用方回退,绝不把空 mesh 塞进 Mesh)
Scope<Model> Model::CreatePrimitive(Device& device, MemoryAllocator& allocator,
DescriptorManager& descriptorManager,
vk::DescriptorSetLayout textureLayout,
const std::string& shape,
const PrimitiveDesc& desc,
u8 r, u8 g, u8 b)
{
// 纯色贴图直供 albedo 槽;生命周期挂进纹理缓存(键含 rgba 值,
// 同色共享、异色互不冲突)——与平面 ctor 同一套
InitDefaultTextures();
Scope<Texture> tex = Texture::CreateSolidColor(device, allocator,
rgba[0], rgba[1], rgba[2]);
Texture* albedoOverride = tex.get();
const std::string texKey = "proc-cube:" + std::to_string(rgba[0]) + ',' +
std::to_string(rgba[1]) + ',' + std::to_string(rgba[2]) + ',' +
std::to_string(rgba[3]);
m_TextureCache.emplace(texKey, std::move(tex));
if (!MeshFactory::IsKnownShape(shape)) return nullptr;
MeshData geo = MeshFactory::Make(shape, desc);
if (geo.vertices.empty() || geo.indices.empty()) return nullptr;
const f32 h = halfSize;
// 逐面 4 顶点(底左/底右/顶右/顶左,从面外看)+ 单位 UV
const glm::vec3 P[24] = {
// +Z(前)
{-h,-h, h}, { h,-h, h}, { h, h, h}, {-h, h, h},
// -Z(后)
{ h,-h,-h}, {-h,-h,-h}, {-h, h,-h}, { h, h,-h},
// +Y(上)
{-h, h, h}, { h, h, h}, { h, h,-h}, {-h, h,-h},
// -Y(下)
{-h,-h,-h}, { h,-h,-h}, { h,-h, h}, {-h,-h, h},
// +X(右)
{ h,-h, h}, { h,-h,-h}, { h, h,-h}, { h, h, h},
// -X(左)
{-h,-h,-h}, {-h,-h, h}, {-h, h, h}, {-h, h,-h},
};
const glm::vec3 N[6] = {
{0, 0, 1}, {0, 0, -1}, {0, 1, 0}, {0, -1, 0}, {1, 0, 0}, {-1, 0, 0},
};
const glm::vec2 UV[4] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
std::vector<Vertex> vertices;
vertices.reserve(24);
for (u32 f = 0; f < 6; ++f) {
for (u32 i = 0; i < 4; ++i) {
vertices.push_back({P[f * 4 + i], N[f], UV[i]});
}
// 显示名 = 形状名首字母大写(编辑器材质槽显示用)
std::string name = shape;
if (!name.empty()) {
name[0] = static_cast<char>(std::toupper(
static_cast<unsigned char>(name[0])));
}
std::vector<u32> indices;
indices.reserve(36);
for (u32 f = 0; f < 6; ++f) {
const u32 b = f * 4;
const std::vector<u32> quad = {b, b + 1, b + 2, b, b + 2, b + 3};
indices.insert(indices.end(), quad.begin(), quad.end());
}
const std::vector<std::vector<u32>> lodIndices = {indices};
std::string paths[Material::kSlotCount] = {"", "", "", ""};
std::array<Texture*, Material::kSlotCount> overrides{};
overrides[Material::Albedo] = albedoOverride;
Material* mat = GetOrCreateMaterial(paths, MaterialParams{}, false,
overrides);
m_Meshes.push_back(CreateScope<Mesh>(
m_Device, m_Allocator, vertices, lodIndices, mat));
// 内建材质快照(与 m_Meshes 下标对齐,编辑器材质槽 UI 不越界)
m_MeshMaterialInfos.push_back(
{"Cube", {}, MaterialParams{}, false});
RebuildUnionBounds();
return Scope<Model>(new Model(device, allocator, descriptorManager,
textureLayout, ProceduralTag{},
std::move(geo),
std::array<u8, 4>{r, g, b, 255}, false,
name));
}
// 资产显示名:文件 stem;无信息量(空 / 导入资产库的 "asset")时读