ADD: planet quadtree stabilized

This commit is contained in:
2025-12-29 17:33:11 +09:00
parent dd97019264
commit 56e10d9983
3 changed files with 341 additions and 63 deletions

View File

@@ -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.