7.0 KiB
7.0 KiB
Asset Manager
Centralized asset path resolution, glTF loading, and runtime mesh creation (including simple materials and primitives). Avoids scattered relative paths and duplicates by resolving roots at runtime and caching results.
Path Resolution
- Environment root: Honors
VKG_ASSET_ROOT(expected to containassets/and/orshaders/). - Upward search: If unset, searches upward from the current directory for folders named
assetsandshaders. - Fallbacks: Tries
./assets,../assetsand./shaders,../shaders. - Methods:
shaderPath(name),assetPath(name), andmodelPath(name)(alias ofassetPath). Relative or absolute input is returned if already valid; otherwise resolution is attempted as above.
Access the manager anywhere via EngineContext:
auto *assets = context->getAssets();
auto spv = assets->shaderPath("mesh.vert.spv");
auto chairPath = assets->modelPath("models/chair.glb");
API Summary
- Paths
std::string shaderPath(std::string_view)std::string assetPath(std::string_view)/modelPath(std::string_view)
- glTF
std::optional<std::shared_ptr<LoadedGLTF>> loadGLTF(std::string_view nameOrPath)— cached by canonical absolute path
- Meshes
std::shared_ptr<MeshAsset> createMesh(const MeshCreateInfo &info)std::shared_ptr<MeshAsset> createMesh(const std::string &name, std::span<Vertex> v, std::span<uint32_t> i, std::shared_ptr<GLTFMaterial> material = {})std::shared_ptr<MeshAsset> getMesh(const std::string &name) conststd::shared_ptr<MeshAsset> getPrimitive(std::string_view name) const(returns existing default primitives if created)bool removeMesh(const std::string &name)void cleanup()— releases meshes, material buffers, and any images owned by the manager
Mesh Creation Model
Use either the convenience descriptor (MeshCreateInfo) or the direct overload with vertex/index spans.
struct AssetManager::MaterialOptions {
std::string albedoPath; // resolved through AssetManager
std::string metalRoughPath; // resolved through AssetManager
bool albedoSRGB = true; // VK_FORMAT_R8G8B8A8_SRGB when true
bool metalRoughSRGB = false; // VK_FORMAT_R8G8B8A8_UNORM when false
GLTFMetallic_Roughness::MaterialConstants constants{};
MaterialPass pass = MaterialPass::MainColor; // or Transparent
};
struct AssetManager::MeshGeometryDesc {
enum class Type { Provided, Cube, Sphere };
Type type = Type::Provided;
std::span<Vertex> vertices{}; // when Provided
std::span<uint32_t> indices{}; // when Provided
int sectors = 16; // for Sphere
int stacks = 16; // for Sphere
};
struct AssetManager::MeshMaterialDesc {
enum class Kind { Default, Textured };
Kind kind = Kind::Default;
MaterialOptions options{}; // used when Textured
};
struct AssetManager::MeshCreateInfo {
std::string name; // cache key; reused if already created
MeshGeometryDesc geometry; // Provided / Cube / Sphere
MeshMaterialDesc material; // Default or Textured
};
Behavior and lifetime:
- Default material: If no material is given, a white material is created (2× white textures, per-mesh UBO with sane defaults).
- Textured material: When
MeshMaterialDesc::Textured, images are loaded viastb_imageand uploaded; per-mesh UBO is allocated and filled fromconstants. - Ownership: Material buffers and any images created by the AssetManager are tracked and destroyed on
removeMesh(name)orcleanup(). - Caching: Meshes are cached by
name. Re-creating with the same name returns the existing mesh (no new uploads).
Examples
Create a simple plane and render it (default material):
std::vector<Vertex> v = {
{{-0.5f, 0.0f, -0.5f}, 0.0f, {0,1,0}, 0.0f, {1,1,1,1}},
{{ 0.5f, 0.0f, -0.5f}, 1.0f, {0,1,0}, 0.0f, {1,1,1,1}},
{{-0.5f, 0.0f, 0.5f}, 0.0f, {0,1,0}, 1.0f, {1,1,1,1}},
{{ 0.5f, 0.0f, 0.5f}, 1.0f, {0,1,0}, 1.0f, {1,1,1,1}},
};
std::vector<uint32_t> i = { 0,1,2, 2,1,3 };
auto plane = ctx->getAssets()->createMesh("plane", v, i); // default white material
glm::mat4 xform = glm::scale(glm::mat4(1.f), glm::vec3(10.f, 1.f, 10.f));
ctx->scene->addMeshInstance("ground", plane, xform);
Generate primitives via MeshCreateInfo:
AssetManager::MeshCreateInfo ci{};
ci.name = "cubeA";
ci.geometry.type = AssetManager::MeshGeometryDesc::Type::Cube;
ci.material.kind = AssetManager::MeshMaterialDesc::Kind::Default;
auto cube = ctx->getAssets()->createMesh(ci);
ctx->scene->addMeshInstance("cube.instance", cube,
glm::translate(glm::mat4(1.f), glm::vec3(-2.f, 0.f, -2.f)));
AssetManager::MeshCreateInfo si{};
si.name = "sphere48x24";
si.geometry.type = AssetManager::MeshGeometryDesc::Type::Sphere;
si.geometry.sectors = 48; si.geometry.stacks = 24;
si.material.kind = AssetManager::MeshMaterialDesc::Kind::Default;
auto sphere = ctx->getAssets()->createMesh(si);
ctx->scene->addMeshInstance("sphere.instance", sphere,
glm::translate(glm::mat4(1.f), glm::vec3(2.f, 0.f, -2.f)));
Textured primitive (albedo + metal-rough):
AssetManager::MeshCreateInfo ti{};
ti.name = "ground.textured";
// provide vertices/indices for a plane (see first example)
ti.geometry.type = AssetManager::MeshGeometryDesc::Type::Provided;
ti.geometry.vertices = std::span<Vertex>(v.data(), v.size());
ti.geometry.indices = std::span<uint32_t>(i.data(), i.size());
ti.material.kind = AssetManager::MeshMaterialDesc::Kind::Textured;
ti.material.options.albedoPath = "textures/ground_albedo.png"; // sRGB
ti.material.options.metalRoughPath = "textures/ground_mr.png"; // UNORM
// ti.material.options.pass = MaterialPass::Transparent; // optional
auto texturedPlane = ctx->getAssets()->createMesh(ti);
glm::mat4 tx = glm::scale(glm::mat4(1.f), glm::vec3(10.f, 1.f, 10.f));
ctx->scene->addMeshInstance("ground.textured", texturedPlane, tx);
Textured cube/sphere via options is analogous — set geometry.type to Cube or Sphere and fill material.options.
Runtime glTF spawning:
auto chair = ctx->getAssets()->loadGLTF("models/chair.glb");
if (chair)
{
glm::mat4 t = glm::translate(glm::mat4(1.f), glm::vec3(0.f, 0.f, -3.f));
ctx->scene->addGLTFInstance("chair01", *chair, t);
}
// Move / overwrite
ctx->scene->addGLTFInstance("chair01", *chair,
glm::translate(glm::mat4(1.f), glm::vec3(0.f, 0.5f, -3.f)));
// Remove
ctx->scene->removeGLTFInstance("chair01");
Notes
- Default primitives: The engine creates default Cube/Sphere meshes via
AssetManagerand registers them as dynamic scene instances. - Reuse by name:
createMesh("name", ...)returns the cached mesh if it already exists. Use a unique name or callremoveMesh(name)to replace. - sRGB/UNORM: Albedo is sRGB by default, metal-rough is UNORM by default. Adjust via
MaterialOptions. - Hot reload: Shaders are resolved via
shaderPath(); pipeline hot reload is handled by the pipeline manager, not the AssetManager. - Normal maps: Not wired into the default GLTF PBR material in this branch. Adding them would require descriptor and shader updates.