ADD: planet quadtree stabilized
This commit is contained in:
@@ -22,15 +22,22 @@ auto chairPath = assets->modelPath("models/chair.glb");
|
||||
- Paths
|
||||
- `std::string shaderPath(std::string_view)`
|
||||
- `std::string assetPath(std::string_view)` / `modelPath(std::string_view)`
|
||||
- `const AssetPaths& paths() const` / `void setPaths(const AssetPaths &p)` — get/set asset paths
|
||||
- glTF
|
||||
- `std::optional<std::shared_ptr<LoadedGLTF>> loadGLTF(std::string_view nameOrPath)` — cached by canonical absolute path
|
||||
- `std::optional<std::shared_ptr<LoadedGLTF>> loadGLTF(std::string_view nameOrPath, const GLTFLoadCallbacks *cb)` — with custom callbacks
|
||||
- `size_t prefetchGLTFTextures(std::string_view nameOrPath)` — schedule texture loads ahead of time
|
||||
- `GLTFTexturePrefetchResult prefetchGLTFTexturesWithHandles(std::string_view nameOrPath)` — returns handles for tracking
|
||||
- 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> createMesh(const std::string &name, std::span<Vertex> v, std::span<uint32_t> i, std::shared_ptr<GLTFMaterial> material = {}, bool build_bvh = true)`
|
||||
- `std::shared_ptr<MeshAsset> getMesh(const std::string &name) const`
|
||||
- `std::shared_ptr<MeshAsset> getPrimitive(std::string_view name) const` (returns existing default primitives if created)
|
||||
- `std::shared_ptr<MeshAsset> getPrimitive(std::string_view name) const` — returns existing default primitives if created
|
||||
- `bool removeMesh(const std::string &name)`
|
||||
- `bool removeMeshDeferred(const std::string &name, DeletionQueue &dq)` — deferred cleanup via deletion queue
|
||||
- `void cleanup()` — releases meshes, material buffers, and any images owned by the manager
|
||||
- Materials
|
||||
- `std::shared_ptr<GLTFMaterial> createMaterialFromConstants(const std::string &name, const GLTFMetallic_Roughness::MaterialConstants &constants, MaterialPass pass = MaterialPass::MainColor)` — create PBR material from constants using engine default textures
|
||||
|
||||
### Mesh Creation Model
|
||||
|
||||
@@ -41,15 +48,19 @@ struct AssetManager::MaterialOptions {
|
||||
std::string albedoPath; // resolved through AssetManager
|
||||
std::string metalRoughPath; // resolved through AssetManager
|
||||
std::string normalPath; // resolved through AssetManager (tangent-space normal)
|
||||
std::string occlusionPath; // resolved through AssetManager (ambient occlusion)
|
||||
std::string emissivePath; // resolved through AssetManager (emissive/glow)
|
||||
bool albedoSRGB = true; // VK_FORMAT_R8G8B8A8_SRGB when true
|
||||
bool metalRoughSRGB = false; // VK_FORMAT_R8G8B8A8_UNORM when false
|
||||
bool normalSRGB = false; // normal maps should be UNORM
|
||||
bool occlusionSRGB = false; // occlusion should be UNORM
|
||||
bool emissiveSRGB = true; // emissive is typically sRGB
|
||||
GLTFMetallic_Roughness::MaterialConstants constants{}; // extra[0].x as normalScale
|
||||
MaterialPass pass = MaterialPass::MainColor; // or Transparent
|
||||
};
|
||||
|
||||
struct AssetManager::MeshGeometryDesc {
|
||||
enum class Type { Provided, Cube, Sphere };
|
||||
enum class Type { Provided, Cube, Sphere, Plane, Capsule };
|
||||
Type type = Type::Provided;
|
||||
std::span<Vertex> vertices{}; // when Provided
|
||||
std::span<uint32_t> indices{}; // when Provided
|
||||
@@ -65,8 +76,9 @@ struct AssetManager::MeshMaterialDesc {
|
||||
|
||||
struct AssetManager::MeshCreateInfo {
|
||||
std::string name; // cache key; reused if already created
|
||||
MeshGeometryDesc geometry; // Provided / Cube / Sphere
|
||||
MeshGeometryDesc geometry; // Provided / Cube / Sphere / Plane / Capsule
|
||||
MeshMaterialDesc material; // Default or Textured
|
||||
std::optional<BoundsType> boundsType; // optional override for collision/picking bounds
|
||||
};
|
||||
```
|
||||
|
||||
@@ -113,9 +125,23 @@ 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)));
|
||||
|
||||
// Plane primitive
|
||||
AssetManager::MeshCreateInfo pi{};
|
||||
pi.name = "groundPlane";
|
||||
pi.geometry.type = AssetManager::MeshGeometryDesc::Type::Plane;
|
||||
pi.material.kind = AssetManager::MeshMaterialDesc::Kind::Default;
|
||||
auto plane = ctx->getAssets()->createMesh(pi);
|
||||
|
||||
// Capsule primitive
|
||||
AssetManager::MeshCreateInfo capi{};
|
||||
capi.name = "capsuleA";
|
||||
capi.geometry.type = AssetManager::MeshGeometryDesc::Type::Capsule;
|
||||
capi.material.kind = AssetManager::MeshMaterialDesc::Kind::Default;
|
||||
auto capsule = ctx->getAssets()->createMesh(capi);
|
||||
```
|
||||
|
||||
Textured primitive (albedo + metal-rough + normal):
|
||||
Textured primitive (albedo + metal-rough + normal + occlusion + emissive):
|
||||
|
||||
```c++
|
||||
AssetManager::MeshCreateInfo ti{};
|
||||
@@ -128,6 +154,8 @@ 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, G=roughness, B=metallic
|
||||
ti.material.options.normalPath = "textures/ground_n.png"; // UNORM
|
||||
ti.material.options.occlusionPath = "textures/ground_ao.png"; // UNORM (optional)
|
||||
ti.material.options.emissivePath = "textures/ground_emit.png"; // sRGB (optional)
|
||||
ti.material.options.constants.extra[0].x = 1.0f; // normalScale
|
||||
// ti.material.options.pass = MaterialPass::Transparent; // optional
|
||||
|
||||
@@ -136,7 +164,25 @@ 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`.
|
||||
Textured cube/sphere/plane/capsule via options is analogous — set `geometry.type` to `Cube`, `Sphere`, `Plane`, or `Capsule` and fill `material.options`.
|
||||
|
||||
Using custom material from constants:
|
||||
|
||||
```c++
|
||||
// Create a material with custom PBR values (using engine default textures)
|
||||
GLTFMetallic_Roughness::MaterialConstants constants{};
|
||||
constants.colorFactors = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); // red
|
||||
constants.metal_rough_factors = glm::vec4(0.0f, 0.8f, 0.0f, 0.0f); // non-metallic, rough
|
||||
|
||||
auto redMaterial = ctx->getAssets()->createMaterialFromConstants(
|
||||
"red_rough_material",
|
||||
constants,
|
||||
MaterialPass::MainColor
|
||||
);
|
||||
|
||||
// Use with custom mesh
|
||||
auto mesh = ctx->getAssets()->createMesh("custom_mesh", vertices, indices, redMaterial);
|
||||
```
|
||||
|
||||
Runtime glTF spawning:
|
||||
|
||||
@@ -154,11 +200,74 @@ ctx->scene->addGLTFInstance("chair01", *chair,
|
||||
ctx->scene->removeGLTFInstance("chair01");
|
||||
```
|
||||
|
||||
### Texture Prefetching
|
||||
|
||||
Queue texture loads for a glTF file ahead of time. This parses the glTF, builds TextureCache keys for referenced images (both external URIs and embedded images in buffers), and issues `TextureCache::request()` calls. Actual uploads happen via the normal per-frame pump.
|
||||
|
||||
```c++
|
||||
// Simple version: returns number of textures scheduled
|
||||
size_t count = ctx->getAssets()->prefetchGLTFTextures("models/heavy_asset.glb");
|
||||
|
||||
// Advanced version: returns handles for tracking progress
|
||||
auto result = ctx->getAssets()->prefetchGLTFTexturesWithHandles("models/heavy_asset.glb");
|
||||
fmt::println("Scheduled {} textures", result.scheduled);
|
||||
// Use result.handles with TextureCache to monitor loading state
|
||||
```
|
||||
|
||||
Texture prefetching is particularly useful when combined with `AsyncAssetLoader` for loading large models in the background.
|
||||
|
||||
### Async Asset Loading
|
||||
|
||||
The `AsyncAssetLoader` class provides asynchronous glTF loading with worker threads for CPU-bound tasks (file I/O, parsing, mesh/BVH building). GPU uploads are still deferred through ResourceManager and the Render Graph.
|
||||
|
||||
```c++
|
||||
// Access via EngineContext
|
||||
auto *loader = ctx->async_loader;
|
||||
|
||||
// Queue a model to load in the background
|
||||
auto jobID = loader->load_gltf_async(
|
||||
"spaceship_01", // scene instance name
|
||||
"models/spaceship.glb", // model path (resolved via AssetManager)
|
||||
glm::translate(glm::mat4(1.f), glm::vec3(0, 5, -10)), // transform
|
||||
true // preload textures
|
||||
);
|
||||
|
||||
// Check progress in your update loop
|
||||
JobState state;
|
||||
float progress;
|
||||
std::string error;
|
||||
if (loader->get_job_status(jobID, state, progress, &error)) {
|
||||
if (state == JobState::Completed) {
|
||||
fmt::println("Model loaded successfully!");
|
||||
} else if (state == JobState::Failed) {
|
||||
fmt::println("Failed to load: {}", error);
|
||||
}
|
||||
}
|
||||
|
||||
// Commit completed jobs to the scene (call once per frame)
|
||||
loader->pump_main_thread(*ctx->scene);
|
||||
|
||||
// Alternative: use WorldVec3 for large-world coordinates
|
||||
auto jobID2 = loader->load_gltf_async(
|
||||
"distant_building",
|
||||
"models/building.glb",
|
||||
WorldVec3{1000000.0, 0.0, 500000.0}, // world position
|
||||
glm::quat(1.0f, 0.0f, 0.0f, 0.0f), // rotation
|
||||
glm::vec3(1.0f), // scale
|
||||
false // don't preload textures
|
||||
);
|
||||
```
|
||||
|
||||
The `AsyncAssetLoader` integrates with `TextureCache` to track texture streaming progress. When `preload_textures` is true, the loader will schedule all model textures for loading and track their residency state.
|
||||
|
||||
### Notes
|
||||
|
||||
- Default primitives: The engine creates default Cube/Sphere meshes via `AssetManager` and registers them as dynamic scene instances.
|
||||
- Default primitives: The engine creates default Cube/Sphere/Plane/Capsule meshes via `AssetManager` and registers them as dynamic scene instances.
|
||||
- Reuse by name: `createMesh("name", ...)` returns the cached mesh if it already exists. Use a unique name or call `removeMesh(name)` to replace.
|
||||
- sRGB/UNORM: Albedo is sRGB by default, metal-rough is UNORM by default. Adjust via `MaterialOptions`.
|
||||
- sRGB/UNORM: Albedo and emissive are sRGB by default, metal-rough/normal/occlusion are 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: Supported. If `normalPath` is empty, a flat normal is used.
|
||||
- Occlusion & Emissive: Supported via `occlusionPath` and `emissivePath` in `MaterialOptions`.
|
||||
- Tangents: Loaded from glTF when present; otherwise generated. Enable MikkTSpace at configure time with `-DENABLE_MIKKTS=ON`.
|
||||
- BVH building: Enabled by default for meshes (`build_bvh = true`). Required for picking and ray-tracing.
|
||||
- Deferred cleanup: Use `removeMeshDeferred()` when destroying meshes during rendering to avoid destroying resources that are in-flight on the GPU.
|
||||
|
||||
Reference in New Issue
Block a user