ADD: planet quadtree buffer, draw improvement
This commit is contained in:
@@ -359,6 +359,44 @@ GPUMeshBuffers ResourceManager::uploadMesh(std::span<uint32_t> indices, std::spa
|
|||||||
return newSurface;
|
return newSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AllocatedBuffer ResourceManager::upload_buffer(const void *data, size_t size, VkBufferUsageFlags usage,
|
||||||
|
VmaMemoryUsage memoryUsage)
|
||||||
|
{
|
||||||
|
if (data == nullptr || size == 0)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
AllocatedBuffer dst = create_buffer(size, usage | VK_BUFFER_USAGE_TRANSFER_DST_BIT, memoryUsage);
|
||||||
|
|
||||||
|
AllocatedBuffer staging = create_buffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
|
VMA_MEMORY_USAGE_CPU_ONLY);
|
||||||
|
|
||||||
|
memcpy(staging.info.pMappedData, data, size);
|
||||||
|
vmaFlushAllocation(_deviceManager->allocator(), staging.allocation, 0, size);
|
||||||
|
|
||||||
|
PendingBufferUpload pending{};
|
||||||
|
pending.staging = staging;
|
||||||
|
pending.copies.push_back(BufferCopyRegion{
|
||||||
|
.destination = dst.buffer,
|
||||||
|
.dstOffset = 0,
|
||||||
|
.size = size,
|
||||||
|
.stagingOffset = 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(_pendingMutex);
|
||||||
|
_pendingBufferUploads.push_back(std::move(pending));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_deferUploads)
|
||||||
|
{
|
||||||
|
process_queued_uploads_immediate();
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
bool ResourceManager::has_pending_uploads() const
|
bool ResourceManager::has_pending_uploads() const
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lk(_pendingMutex);
|
std::lock_guard<std::mutex> lk(_pendingMutex);
|
||||||
|
|||||||
@@ -94,6 +94,12 @@ public:
|
|||||||
|
|
||||||
GPUMeshBuffers uploadMesh(std::span<uint32_t> indices, std::span<Vertex> vertices);
|
GPUMeshBuffers uploadMesh(std::span<uint32_t> indices, std::span<Vertex> vertices);
|
||||||
|
|
||||||
|
// Upload raw bytes into a GPU buffer. The destination buffer is created with the provided 'usage'
|
||||||
|
// flags plus VK_BUFFER_USAGE_TRANSFER_DST_BIT. Staging is handled internally and freed via the
|
||||||
|
// per-frame deletion queue when deferred uploads are enabled.
|
||||||
|
AllocatedBuffer upload_buffer(const void *data, size_t size, VkBufferUsageFlags usage,
|
||||||
|
VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY);
|
||||||
|
|
||||||
void immediate_submit(std::function<void(VkCommandBuffer)> &&function) const;
|
void immediate_submit(std::function<void(VkCommandBuffer)> &&function) const;
|
||||||
|
|
||||||
bool has_pending_uploads() const;
|
bool has_pending_uploads() const;
|
||||||
|
|||||||
@@ -83,38 +83,114 @@ namespace planet
|
|||||||
return glm::max(10.0, 0.02 * edge_m);
|
return glm::max(10.0, 0.02 * edge_m);
|
||||||
}
|
}
|
||||||
|
|
||||||
void build_cubesphere_patch_mesh(CubeSpherePatchMesh &out,
|
void build_cubesphere_patch_indices(std::vector<uint32_t> &out_indices, uint32_t resolution)
|
||||||
const WorldVec3 ¢er_world,
|
{
|
||||||
|
out_indices.clear();
|
||||||
|
|
||||||
|
if (resolution < 2)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t grid_index_count =
|
||||||
|
static_cast<size_t>(resolution - 1u) * static_cast<size_t>(resolution - 1u) * 6u;
|
||||||
|
const size_t skirt_index_count = static_cast<size_t>(4u) * static_cast<size_t>(resolution - 1u) * 6u;
|
||||||
|
out_indices.reserve(grid_index_count + skirt_index_count);
|
||||||
|
|
||||||
|
// Base grid indices
|
||||||
|
for (uint32_t j = 0; j + 1 < resolution; ++j)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i + 1 < resolution; ++i)
|
||||||
|
{
|
||||||
|
const uint32_t i0 = j * resolution + i;
|
||||||
|
const uint32_t i1 = i0 + 1;
|
||||||
|
const uint32_t i2 = i0 + resolution;
|
||||||
|
const uint32_t i3 = i2 + 1;
|
||||||
|
|
||||||
|
// CCW winding when viewed from outside the sphere.
|
||||||
|
out_indices.push_back(i0);
|
||||||
|
out_indices.push_back(i1);
|
||||||
|
out_indices.push_back(i2);
|
||||||
|
|
||||||
|
out_indices.push_back(i2);
|
||||||
|
out_indices.push_back(i1);
|
||||||
|
out_indices.push_back(i3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto add_skirt_quads = [&](uint32_t base0, uint32_t base1, uint32_t skirt0, uint32_t skirt1)
|
||||||
|
{
|
||||||
|
out_indices.push_back(base0);
|
||||||
|
out_indices.push_back(base1);
|
||||||
|
out_indices.push_back(skirt0);
|
||||||
|
|
||||||
|
out_indices.push_back(skirt0);
|
||||||
|
out_indices.push_back(base1);
|
||||||
|
out_indices.push_back(skirt1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32_t base_vertex_count = resolution * resolution;
|
||||||
|
const uint32_t top_skirt_start = base_vertex_count + 0u * resolution;
|
||||||
|
const uint32_t right_skirt_start = base_vertex_count + 1u * resolution;
|
||||||
|
const uint32_t bottom_skirt_start = base_vertex_count + 2u * resolution;
|
||||||
|
const uint32_t left_skirt_start = base_vertex_count + 3u * resolution;
|
||||||
|
|
||||||
|
// Skirt indices: 4 edges, (N-1) segments each.
|
||||||
|
for (uint32_t i = 0; i + 1 < resolution; ++i)
|
||||||
|
{
|
||||||
|
// Top edge
|
||||||
|
add_skirt_quads(0u * resolution + i,
|
||||||
|
0u * resolution + (i + 1u),
|
||||||
|
top_skirt_start + i,
|
||||||
|
top_skirt_start + (i + 1u));
|
||||||
|
// Bottom edge
|
||||||
|
add_skirt_quads((resolution - 1u) * resolution + i,
|
||||||
|
(resolution - 1u) * resolution + (i + 1u),
|
||||||
|
bottom_skirt_start + i,
|
||||||
|
bottom_skirt_start + (i + 1u));
|
||||||
|
}
|
||||||
|
for (uint32_t j = 0; j + 1 < resolution; ++j)
|
||||||
|
{
|
||||||
|
// Left edge
|
||||||
|
add_skirt_quads(j * resolution + 0u,
|
||||||
|
(j + 1u) * resolution + 0u,
|
||||||
|
left_skirt_start + j,
|
||||||
|
left_skirt_start + (j + 1u));
|
||||||
|
// Right edge
|
||||||
|
add_skirt_quads(j * resolution + (resolution - 1u),
|
||||||
|
(j + 1u) * resolution + (resolution - 1u),
|
||||||
|
right_skirt_start + j,
|
||||||
|
right_skirt_start + (j + 1u));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::dvec3 build_cubesphere_patch_vertices(std::vector<Vertex> &out_vertices,
|
||||||
double radius_m,
|
double radius_m,
|
||||||
CubeFace face,
|
CubeFace face,
|
||||||
uint32_t level,
|
uint32_t level,
|
||||||
uint32_t x,
|
uint32_t x,
|
||||||
uint32_t y,
|
uint32_t y,
|
||||||
uint32_t resolution,
|
uint32_t resolution,
|
||||||
const glm::vec4 &vertex_color,
|
const glm::vec4 &vertex_color)
|
||||||
bool generate_tangents)
|
|
||||||
{
|
{
|
||||||
out.vertices.clear();
|
out_vertices.clear();
|
||||||
out.indices.clear();
|
|
||||||
out.patch_center_world = center_world;
|
|
||||||
|
|
||||||
if (resolution < 2)
|
if (resolution < 2)
|
||||||
{
|
{
|
||||||
return;
|
return glm::dvec3(0.0, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const glm::dvec3 patch_center_dir = cubesphere_patch_center_direction(face, level, x, y);
|
||||||
|
|
||||||
const double skirt_depth_m = cubesphere_skirt_depth_m(radius_m, level);
|
const double skirt_depth_m = cubesphere_skirt_depth_m(radius_m, level);
|
||||||
const double skirt_radius_m = glm::max(0.0, radius_m - skirt_depth_m);
|
const double skirt_radius_m = glm::max(0.0, radius_m - skirt_depth_m);
|
||||||
|
|
||||||
double u0 = 0.0, u1 = 0.0, v0 = 0.0, v1 = 0.0;
|
double u0 = 0.0, u1 = 0.0, v0 = 0.0, v1 = 0.0;
|
||||||
cubesphere_tile_uv_bounds(level, x, y, u0, u1, v0, v1);
|
cubesphere_tile_uv_bounds(level, x, y, u0, u1, v0, v1);
|
||||||
|
|
||||||
const glm::dvec3 patch_center_dir = cubesphere_patch_center_direction(face, level, x, y);
|
|
||||||
out.patch_center_world = center_world + patch_center_dir * radius_m;
|
|
||||||
|
|
||||||
const uint32_t base_vertex_count = resolution * resolution;
|
const uint32_t base_vertex_count = resolution * resolution;
|
||||||
const uint32_t skirt_vertex_count = 4u * resolution;
|
const uint32_t skirt_vertex_count = 4u * resolution;
|
||||||
out.vertices.resize(static_cast<size_t>(base_vertex_count) + static_cast<size_t>(skirt_vertex_count));
|
out_vertices.resize(static_cast<size_t>(base_vertex_count) + static_cast<size_t>(skirt_vertex_count));
|
||||||
|
|
||||||
const double inv = 1.0 / static_cast<double>(resolution - 1u);
|
const double inv = 1.0 / static_cast<double>(resolution - 1u);
|
||||||
const double du = (u1 - u0) * inv;
|
const double du = (u1 - u0) * inv;
|
||||||
@@ -145,26 +221,26 @@ namespace planet
|
|||||||
vert.tangent = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f);
|
vert.tangent = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
const uint32_t idx = j * resolution + i;
|
const uint32_t idx = j * resolution + i;
|
||||||
out.vertices[idx] = vert;
|
out_vertices[idx] = vert;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto add_skirt_vertex = [&](uint32_t base_index, uint32_t skirt_index)
|
auto add_skirt_vertex = [&](uint32_t base_index, uint32_t skirt_index)
|
||||||
{
|
{
|
||||||
const glm::vec3 n = out.vertices[base_index].normal;
|
const glm::vec3 n = out_vertices[base_index].normal;
|
||||||
const glm::dvec3 unit_dir(static_cast<double>(n.x),
|
const glm::dvec3 unit_dir(static_cast<double>(n.x),
|
||||||
static_cast<double>(n.y),
|
static_cast<double>(n.y),
|
||||||
static_cast<double>(n.z));
|
static_cast<double>(n.z));
|
||||||
const glm::dvec3 delta_d = unit_dir * skirt_radius_m - patch_center_dir * radius_m;
|
const glm::dvec3 delta_d = unit_dir * skirt_radius_m - patch_center_dir * radius_m;
|
||||||
|
|
||||||
Vertex vert = out.vertices[base_index];
|
Vertex vert = out_vertices[base_index];
|
||||||
vert.position = glm::vec3(static_cast<float>(delta_d.x),
|
vert.position = glm::vec3(static_cast<float>(delta_d.x),
|
||||||
static_cast<float>(delta_d.y),
|
static_cast<float>(delta_d.y),
|
||||||
static_cast<float>(delta_d.z));
|
static_cast<float>(delta_d.z));
|
||||||
vert.normal = glm::vec3(static_cast<float>(unit_dir.x),
|
vert.normal = glm::vec3(static_cast<float>(unit_dir.x),
|
||||||
static_cast<float>(unit_dir.y),
|
static_cast<float>(unit_dir.y),
|
||||||
static_cast<float>(unit_dir.z));
|
static_cast<float>(unit_dir.z));
|
||||||
out.vertices[skirt_index] = vert;
|
out_vertices[skirt_index] = vert;
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint32_t top_skirt_start = base_vertex_count + 0u * resolution;
|
const uint32_t top_skirt_start = base_vertex_count + 0u * resolution;
|
||||||
@@ -193,70 +269,34 @@ namespace planet
|
|||||||
add_skirt_vertex(j * resolution + 0u, left_skirt_start + j);
|
add_skirt_vertex(j * resolution + 0u, left_skirt_start + j);
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t grid_index_count =
|
return patch_center_dir;
|
||||||
static_cast<size_t>(resolution - 1u) * static_cast<size_t>(resolution - 1u) * 6u;
|
|
||||||
const size_t skirt_index_count = static_cast<size_t>(4u) * static_cast<size_t>(resolution - 1u) * 6u;
|
|
||||||
out.indices.reserve(grid_index_count + skirt_index_count);
|
|
||||||
|
|
||||||
// Base grid indices
|
|
||||||
for (uint32_t j = 0; j + 1 < resolution; ++j)
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i + 1 < resolution; ++i)
|
|
||||||
{
|
|
||||||
const uint32_t i0 = j * resolution + i;
|
|
||||||
const uint32_t i1 = i0 + 1;
|
|
||||||
const uint32_t i2 = i0 + resolution;
|
|
||||||
const uint32_t i3 = i2 + 1;
|
|
||||||
|
|
||||||
// CCW winding when viewed from outside the sphere.
|
|
||||||
out.indices.push_back(i0);
|
|
||||||
out.indices.push_back(i1);
|
|
||||||
out.indices.push_back(i2);
|
|
||||||
|
|
||||||
out.indices.push_back(i2);
|
|
||||||
out.indices.push_back(i1);
|
|
||||||
out.indices.push_back(i3);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto add_skirt_quads = [&](uint32_t base0, uint32_t base1, uint32_t skirt0, uint32_t skirt1)
|
void build_cubesphere_patch_mesh(CubeSpherePatchMesh &out,
|
||||||
|
const WorldVec3 ¢er_world,
|
||||||
|
double radius_m,
|
||||||
|
CubeFace face,
|
||||||
|
uint32_t level,
|
||||||
|
uint32_t x,
|
||||||
|
uint32_t y,
|
||||||
|
uint32_t resolution,
|
||||||
|
const glm::vec4 &vertex_color,
|
||||||
|
bool generate_tangents)
|
||||||
{
|
{
|
||||||
out.indices.push_back(base0);
|
out.vertices.clear();
|
||||||
out.indices.push_back(base1);
|
out.indices.clear();
|
||||||
out.indices.push_back(skirt0);
|
out.patch_center_world = center_world;
|
||||||
|
|
||||||
out.indices.push_back(skirt0);
|
if (resolution < 2)
|
||||||
out.indices.push_back(base1);
|
{
|
||||||
out.indices.push_back(skirt1);
|
return;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Skirt indices: 4 edges, (N-1) segments each.
|
const glm::dvec3 patch_center_dir =
|
||||||
for (uint32_t i = 0; i + 1 < resolution; ++i)
|
build_cubesphere_patch_vertices(out.vertices, radius_m, face, level, x, y, resolution, vertex_color);
|
||||||
{
|
build_cubesphere_patch_indices(out.indices, resolution);
|
||||||
// Top edge
|
|
||||||
add_skirt_quads(0u * resolution + i,
|
out.patch_center_world = center_world + patch_center_dir * radius_m;
|
||||||
0u * resolution + (i + 1u),
|
|
||||||
top_skirt_start + i,
|
|
||||||
top_skirt_start + (i + 1u));
|
|
||||||
// Bottom edge
|
|
||||||
add_skirt_quads((resolution - 1u) * resolution + i,
|
|
||||||
(resolution - 1u) * resolution + (i + 1u),
|
|
||||||
bottom_skirt_start + i,
|
|
||||||
bottom_skirt_start + (i + 1u));
|
|
||||||
}
|
|
||||||
for (uint32_t j = 0; j + 1 < resolution; ++j)
|
|
||||||
{
|
|
||||||
// Left edge
|
|
||||||
add_skirt_quads(j * resolution + 0u,
|
|
||||||
(j + 1u) * resolution + 0u,
|
|
||||||
left_skirt_start + j,
|
|
||||||
left_skirt_start + (j + 1u));
|
|
||||||
// Right edge
|
|
||||||
add_skirt_quads(j * resolution + (resolution - 1u),
|
|
||||||
(j + 1u) * resolution + (resolution - 1u),
|
|
||||||
right_skirt_start + j,
|
|
||||||
right_skirt_start + (j + 1u));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (generate_tangents)
|
if (generate_tangents)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -55,6 +55,21 @@ namespace planet
|
|||||||
WorldVec3 patch_center_world{0.0, 0.0, 0.0};
|
WorldVec3 patch_center_world{0.0, 0.0, 0.0};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Build the shared index list for a patch grid with skirts. Indices are identical for all
|
||||||
|
// patches as long as 'resolution' is constant.
|
||||||
|
void build_cubesphere_patch_indices(std::vector<uint32_t> &out_indices, uint32_t resolution);
|
||||||
|
|
||||||
|
// Build patch vertices (including skirts). Vertex positions are relative to the patch center on
|
||||||
|
// the sphere surface (computed from face/level/x/y). Returns the patch center direction.
|
||||||
|
glm::dvec3 build_cubesphere_patch_vertices(std::vector<Vertex> &out_vertices,
|
||||||
|
double radius_m,
|
||||||
|
CubeFace face,
|
||||||
|
uint32_t level,
|
||||||
|
uint32_t x,
|
||||||
|
uint32_t y,
|
||||||
|
uint32_t resolution,
|
||||||
|
const glm::vec4 &vertex_color);
|
||||||
|
|
||||||
// Build a cube-sphere patch mesh with skirts. Vertex positions are relative to patch_center_world.
|
// Build a cube-sphere patch mesh with skirts. Vertex positions are relative to patch_center_world.
|
||||||
void build_cubesphere_patch_mesh(CubeSpherePatchMesh &out,
|
void build_cubesphere_patch_mesh(CubeSpherePatchMesh &out,
|
||||||
const WorldVec3 ¢er_world,
|
const WorldVec3 ¢er_world,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "planet_system.h"
|
#include "planet_system.h"
|
||||||
|
|
||||||
#include <core/context.h>
|
#include <core/context.h>
|
||||||
|
#include <core/device/resource.h>
|
||||||
#include <core/frame/resources.h>
|
#include <core/frame/resources.h>
|
||||||
#include <core/types.h>
|
#include <core/types.h>
|
||||||
#include <core/assets/manager.h>
|
#include <core/assets/manager.h>
|
||||||
@@ -16,12 +17,42 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
constexpr double kEarthRadiusM = 6378137.0; // WGS84 equatorial radius
|
constexpr double kEarthRadiusM = 6378137.0; // WGS84 equatorial radius
|
||||||
constexpr double kMoonRadiusM = 1737400.0; // mean radius
|
constexpr double kMoonRadiusM = 1737400.0; // mean radius
|
||||||
constexpr double kMoonDistanceM = 384400000.0; // mean Earth-Moon distance
|
constexpr double kMoonDistanceM = 384400000.0; // mean Earth-Moon distance
|
||||||
|
|
||||||
|
struct PatchBoundsData
|
||||||
|
{
|
||||||
|
glm::vec3 origin{0.0f};
|
||||||
|
glm::vec3 extents{0.5f};
|
||||||
|
float sphere_radius{0.5f};
|
||||||
|
};
|
||||||
|
|
||||||
|
PatchBoundsData compute_patch_bounds(const std::vector<Vertex> &vertices)
|
||||||
|
{
|
||||||
|
PatchBoundsData b{};
|
||||||
|
if (vertices.empty())
|
||||||
|
{
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 minpos = vertices[0].position;
|
||||||
|
glm::vec3 maxpos = vertices[0].position;
|
||||||
|
for (const auto &v : vertices)
|
||||||
|
{
|
||||||
|
minpos = glm::min(minpos, v.position);
|
||||||
|
maxpos = glm::max(maxpos, v.position);
|
||||||
|
}
|
||||||
|
b.origin = (maxpos + minpos) * 0.5f;
|
||||||
|
b.extents = (maxpos - minpos) * 0.5f;
|
||||||
|
b.sphere_radius = glm::length(b.extents);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
GLTFMetallic_Roughness::MaterialConstants make_planet_constants()
|
GLTFMetallic_Roughness::MaterialConstants make_planet_constants()
|
||||||
{
|
{
|
||||||
GLTFMetallic_Roughness::MaterialConstants c{};
|
GLTFMetallic_Roughness::MaterialConstants c{};
|
||||||
@@ -114,52 +145,193 @@ void PlanetSystem::ensure_bodies_created()
|
|||||||
_bodies.push_back(std::move(moon));
|
_bodies.push_back(std::move(moon));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MeshAsset> PlanetSystem::get_or_create_earth_patch_mesh(const PlanetBody &earth,
|
PlanetSystem::EarthPatch *PlanetSystem::find_earth_patch(const planet::PatchKey &key)
|
||||||
const planet::PatchKey &key)
|
|
||||||
{
|
{
|
||||||
auto it = _earth_patch_cache.find(key);
|
auto it = _earth_patch_lookup.find(key);
|
||||||
if (it != _earth_patch_cache.end())
|
if (it == _earth_patch_lookup.end())
|
||||||
{
|
{
|
||||||
it->second.last_used_frame = _context ? _context->frameIndex : 0;
|
return nullptr;
|
||||||
_earth_patch_lru.splice(_earth_patch_lru.begin(), _earth_patch_lru, it->second.lru_it);
|
}
|
||||||
return it->second.mesh;
|
const uint32_t idx = it->second;
|
||||||
|
if (idx >= _earth_patches.size())
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return &_earth_patches[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlanetSystem::ensure_earth_patch_index_buffer()
|
||||||
|
{
|
||||||
|
if (_earth_patch_index_buffer.buffer != VK_NULL_HANDLE && _earth_patch_index_resolution == _earth_patch_resolution)
|
||||||
|
{
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_context || !_context->assets || !earth.material)
|
if (!_context)
|
||||||
{
|
{
|
||||||
return {};
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
planet::CubeSpherePatchMesh mesh{};
|
ResourceManager *rm = _context->getResources();
|
||||||
planet::build_cubesphere_patch_mesh(mesh,
|
if (!rm)
|
||||||
earth.center_world,
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolution changed (or first init): clear existing patch cache and shared index buffer.
|
||||||
|
if (_earth_patch_index_buffer.buffer != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
FrameResources *frame = _context->currentFrame;
|
||||||
|
|
||||||
|
// Destroy per-patch vertex buffers.
|
||||||
|
for (const auto &kv : _earth_patch_lookup)
|
||||||
|
{
|
||||||
|
const uint32_t idx = kv.second;
|
||||||
|
if (idx >= _earth_patches.size())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
EarthPatch &p = _earth_patches[idx];
|
||||||
|
if (p.vertex_buffer.buffer == VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AllocatedBuffer vb = p.vertex_buffer;
|
||||||
|
if (frame)
|
||||||
|
{
|
||||||
|
frame->_deletionQueue.push_function([rm, vb]() { rm->destroy_buffer(vb); });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rm->destroy_buffer(vb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_earth_patch_lookup.clear();
|
||||||
|
_earth_patch_lru.clear();
|
||||||
|
_earth_patch_free.clear();
|
||||||
|
_earth_patches.clear();
|
||||||
|
|
||||||
|
const AllocatedBuffer ib = _earth_patch_index_buffer;
|
||||||
|
if (frame)
|
||||||
|
{
|
||||||
|
frame->_deletionQueue.push_function([rm, ib]() { rm->destroy_buffer(ib); });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rm->destroy_buffer(ib);
|
||||||
|
}
|
||||||
|
_earth_patch_index_buffer = {};
|
||||||
|
_earth_patch_index_count = 0;
|
||||||
|
_earth_patch_index_resolution = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint32_t> indices;
|
||||||
|
planet::build_cubesphere_patch_indices(indices, _earth_patch_resolution);
|
||||||
|
_earth_patch_index_count = static_cast<uint32_t>(indices.size());
|
||||||
|
_earth_patch_index_buffer =
|
||||||
|
rm->upload_buffer(indices.data(),
|
||||||
|
indices.size() * sizeof(uint32_t),
|
||||||
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
|
||||||
|
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
|
||||||
|
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR);
|
||||||
|
_earth_patch_index_resolution = _earth_patch_resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlanetSystem::EarthPatch *PlanetSystem::get_or_create_earth_patch(const PlanetBody &earth,
|
||||||
|
const planet::PatchKey &key,
|
||||||
|
uint32_t frame_index)
|
||||||
|
{
|
||||||
|
if (EarthPatch *p = find_earth_patch(key))
|
||||||
|
{
|
||||||
|
p->last_used_frame = frame_index;
|
||||||
|
_earth_patch_lru.splice(_earth_patch_lru.begin(), _earth_patch_lru, p->lru_it);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_context)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceManager *rm = _context->getResources();
|
||||||
|
DeviceManager *device = _context->getDevice();
|
||||||
|
if (!rm || !device)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_earth_patch_index_buffer.buffer == VK_NULL_HANDLE || _earth_patch_index_count == 0)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Vertex> vertices;
|
||||||
|
const glm::dvec3 patch_center_dir =
|
||||||
|
planet::build_cubesphere_patch_vertices(vertices,
|
||||||
earth.radius_m,
|
earth.radius_m,
|
||||||
key.face,
|
key.face,
|
||||||
key.level,
|
key.level,
|
||||||
key.x,
|
key.x,
|
||||||
key.y,
|
key.y,
|
||||||
_earth_patch_resolution,
|
_earth_patch_resolution,
|
||||||
debug_color_for_level(key.level),
|
debug_color_for_level(key.level));
|
||||||
/*generate_tangents=*/false);
|
|
||||||
|
|
||||||
const uint32_t face_i = static_cast<uint32_t>(key.face);
|
if (vertices.empty())
|
||||||
const std::string name =
|
{
|
||||||
"Planet_EarthPatch_f" + std::to_string(face_i) +
|
return nullptr;
|
||||||
"_L" + std::to_string(key.level) +
|
}
|
||||||
"_X" + std::to_string(key.x) +
|
|
||||||
"_Y" + std::to_string(key.y);
|
|
||||||
|
|
||||||
std::shared_ptr<MeshAsset> out =
|
const PatchBoundsData bounds = compute_patch_bounds(vertices);
|
||||||
_context->assets->createMesh(name, mesh.vertices, mesh.indices, earth.material, /*build_bvh=*/false);
|
|
||||||
|
|
||||||
EarthPatchCacheEntry entry{};
|
AllocatedBuffer vb =
|
||||||
entry.mesh = out;
|
rm->upload_buffer(vertices.data(),
|
||||||
entry.patch_center_dir = planet::cubesphere_patch_center_direction(key.face, key.level, key.x, key.y);
|
vertices.size() * sizeof(Vertex),
|
||||||
entry.last_used_frame = _context ? _context->frameIndex : 0;
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
||||||
_earth_patch_lru.push_front(key);
|
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
|
||||||
entry.lru_it = _earth_patch_lru.begin();
|
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR);
|
||||||
_earth_patch_cache.emplace(key, std::move(entry));
|
if (vb.buffer == VK_NULL_HANDLE)
|
||||||
return out;
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBufferDeviceAddressInfo addrInfo{.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO};
|
||||||
|
addrInfo.buffer = vb.buffer;
|
||||||
|
VkDeviceAddress addr = vkGetBufferDeviceAddress(device->device(), &addrInfo);
|
||||||
|
|
||||||
|
uint32_t idx = 0;
|
||||||
|
if (!_earth_patch_free.empty())
|
||||||
|
{
|
||||||
|
idx = _earth_patch_free.back();
|
||||||
|
_earth_patch_free.pop_back();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idx = static_cast<uint32_t>(_earth_patches.size());
|
||||||
|
_earth_patches.emplace_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx >= _earth_patches.size())
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
EarthPatch &p = _earth_patches[idx];
|
||||||
|
p.key = key;
|
||||||
|
p.state = EarthPatchState::Ready;
|
||||||
|
p.vertex_buffer = vb;
|
||||||
|
p.vertex_buffer_address = addr;
|
||||||
|
p.bounds_origin = bounds.origin;
|
||||||
|
p.bounds_extents = bounds.extents;
|
||||||
|
p.bounds_sphere_radius = bounds.sphere_radius;
|
||||||
|
p.patch_center_dir = patch_center_dir;
|
||||||
|
p.last_used_frame = frame_index;
|
||||||
|
_earth_patch_lru.push_front(idx);
|
||||||
|
p.lru_it = _earth_patch_lru.begin();
|
||||||
|
|
||||||
|
_earth_patch_lookup.emplace(key, idx);
|
||||||
|
return &p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlanetSystem::trim_earth_patch_cache()
|
void PlanetSystem::trim_earth_patch_cache()
|
||||||
@@ -169,47 +341,73 @@ void PlanetSystem::trim_earth_patch_cache()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_earth_patch_cache.size() <= static_cast<size_t>(_earth_patch_cache_max))
|
if (_earth_patch_lookup.size() <= static_cast<size_t>(_earth_patch_cache_max))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_context || !_context->assets)
|
if (!_context)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceManager *rm = _context->getResources();
|
||||||
|
if (!rm)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetManager *assets = _context->assets;
|
|
||||||
FrameResources *frame = _context->currentFrame;
|
FrameResources *frame = _context->currentFrame;
|
||||||
|
const uint32_t now = _earth_patch_frame_stamp;
|
||||||
|
|
||||||
while (_earth_patch_cache.size() > static_cast<size_t>(_earth_patch_cache_max) && !_earth_patch_lru.empty())
|
size_t guard = 0;
|
||||||
|
const size_t guard_limit = _earth_patch_lru.size();
|
||||||
|
|
||||||
|
while (_earth_patch_lookup.size() > static_cast<size_t>(_earth_patch_cache_max) && !_earth_patch_lru.empty())
|
||||||
|
{
|
||||||
|
if (guard++ >= guard_limit)
|
||||||
|
{
|
||||||
|
// No evictable patches (all used this frame). Avoid thrashing.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t idx = _earth_patch_lru.back();
|
||||||
|
if (idx >= _earth_patches.size())
|
||||||
{
|
{
|
||||||
const planet::PatchKey key = _earth_patch_lru.back();
|
|
||||||
_earth_patch_lru.pop_back();
|
_earth_patch_lru.pop_back();
|
||||||
|
|
||||||
auto it = _earth_patch_cache.find(key);
|
|
||||||
if (it == _earth_patch_cache.end())
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MeshAsset> mesh = std::move(it->second.mesh);
|
EarthPatch &p = _earth_patches[idx];
|
||||||
_earth_patch_cache.erase(it);
|
if (p.last_used_frame == now)
|
||||||
|
|
||||||
if (!mesh)
|
|
||||||
{
|
{
|
||||||
|
// Keep all patches referenced this frame.
|
||||||
|
_earth_patch_lru.splice(_earth_patch_lru.begin(), _earth_patch_lru, p.lru_it);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Made progress: we found an evictable patch.
|
||||||
|
guard = 0;
|
||||||
|
|
||||||
|
_earth_patch_lru.erase(p.lru_it);
|
||||||
|
_earth_patch_lookup.erase(p.key);
|
||||||
|
|
||||||
|
if (p.vertex_buffer.buffer != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
const AllocatedBuffer vb = p.vertex_buffer;
|
||||||
if (frame)
|
if (frame)
|
||||||
{
|
{
|
||||||
assets->removeMeshDeferred(mesh->name, frame->_deletionQueue);
|
frame->_deletionQueue.push_function([rm, vb]() { rm->destroy_buffer(vb); });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assets->removeMesh(mesh->name);
|
rm->destroy_buffer(vb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p = EarthPatch{};
|
||||||
|
_earth_patch_free.push_back(idx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlanetSystem::update_and_emit(const SceneManager &scene, DrawContext &draw_context)
|
void PlanetSystem::update_and_emit(const SceneManager &scene, DrawContext &draw_context)
|
||||||
@@ -246,24 +444,24 @@ void PlanetSystem::update_and_emit(const SceneManager &scene, DrawContext &draw_
|
|||||||
logical_extent);
|
logical_extent);
|
||||||
const Clock::time_point t_q1 = Clock::now();
|
const Clock::time_point t_q1 = Clock::now();
|
||||||
|
|
||||||
|
ensure_earth_patch_index_buffer();
|
||||||
|
|
||||||
uint32_t created_patches = 0;
|
uint32_t created_patches = 0;
|
||||||
double ms_patch_create = 0.0;
|
double ms_patch_create = 0.0;
|
||||||
const uint32_t max_create = _earth_patch_create_budget_per_frame;
|
const uint32_t max_create = _earth_patch_create_budget_per_frame;
|
||||||
const double max_create_ms =
|
const double max_create_ms =
|
||||||
(_earth_patch_create_budget_ms > 0.0f) ? static_cast<double>(_earth_patch_create_budget_ms) : 0.0;
|
(_earth_patch_create_budget_ms > 0.0f) ? static_cast<double>(_earth_patch_create_budget_ms) : 0.0;
|
||||||
const uint32_t frame_index = _context->frameIndex;
|
const uint32_t frame_index = ++_earth_patch_frame_stamp;
|
||||||
|
|
||||||
const Clock::time_point t_emit0 = Clock::now();
|
const Clock::time_point t_emit0 = Clock::now();
|
||||||
for (const planet::PatchKey &k : _earth_quadtree.visible_leaves())
|
for (const planet::PatchKey &k : _earth_quadtree.visible_leaves())
|
||||||
{
|
{
|
||||||
EarthPatchCacheEntry *entry = nullptr;
|
EarthPatch *patch = find_earth_patch(k);
|
||||||
{
|
{
|
||||||
auto it = _earth_patch_cache.find(k);
|
if (patch)
|
||||||
if (it != _earth_patch_cache.end())
|
|
||||||
{
|
{
|
||||||
it->second.last_used_frame = frame_index;
|
patch->last_used_frame = frame_index;
|
||||||
_earth_patch_lru.splice(_earth_patch_lru.begin(), _earth_patch_lru, it->second.lru_it);
|
_earth_patch_lru.splice(_earth_patch_lru.begin(), _earth_patch_lru, patch->lru_it);
|
||||||
entry = &it->second;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -272,54 +470,56 @@ void PlanetSystem::update_and_emit(const SceneManager &scene, DrawContext &draw_
|
|||||||
if (!hit_count_budget && !hit_time_budget)
|
if (!hit_count_budget && !hit_time_budget)
|
||||||
{
|
{
|
||||||
const Clock::time_point t_c0 = Clock::now();
|
const Clock::time_point t_c0 = Clock::now();
|
||||||
(void)get_or_create_earth_patch_mesh(*earth, k);
|
patch = get_or_create_earth_patch(*earth, k, frame_index);
|
||||||
const Clock::time_point t_c1 = Clock::now();
|
const Clock::time_point t_c1 = Clock::now();
|
||||||
|
|
||||||
|
if (patch)
|
||||||
|
{
|
||||||
created_patches++;
|
created_patches++;
|
||||||
|
}
|
||||||
ms_patch_create += std::chrono::duration<double, std::milli>(t_c1 - t_c0).count();
|
ms_patch_create += std::chrono::duration<double, std::milli>(t_c1 - t_c0).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto it2 = _earth_patch_cache.find(k);
|
|
||||||
if (it2 != _earth_patch_cache.end())
|
|
||||||
{
|
|
||||||
entry = &it2->second;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (!patch ||
|
||||||
if (!entry || !entry->mesh || entry->mesh->surfaces.empty())
|
patch->state != EarthPatchState::Ready ||
|
||||||
|
patch->vertex_buffer.buffer == VK_NULL_HANDLE ||
|
||||||
|
patch->vertex_buffer_address == 0 ||
|
||||||
|
_earth_patch_index_buffer.buffer == VK_NULL_HANDLE ||
|
||||||
|
_earth_patch_index_count == 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::shared_ptr<MeshAsset> &mesh = entry->mesh;
|
|
||||||
|
|
||||||
const WorldVec3 patch_center_world =
|
const WorldVec3 patch_center_world =
|
||||||
earth->center_world + entry->patch_center_dir * earth->radius_m;
|
earth->center_world + patch->patch_center_dir * earth->radius_m;
|
||||||
const glm::vec3 patch_center_local = world_to_local(patch_center_world, origin_world);
|
const glm::vec3 patch_center_local = world_to_local(patch_center_world, origin_world);
|
||||||
const glm::mat4 transform = glm::translate(glm::mat4(1.0f), patch_center_local);
|
const glm::mat4 transform = glm::translate(glm::mat4(1.0f), patch_center_local);
|
||||||
|
|
||||||
uint32_t surface_index = 0;
|
Bounds b{};
|
||||||
for (const GeoSurface &surf : mesh->surfaces)
|
b.origin = patch->bounds_origin;
|
||||||
{
|
b.extents = patch->bounds_extents;
|
||||||
|
b.sphereRadius = patch->bounds_sphere_radius;
|
||||||
|
b.type = BoundsType::Box;
|
||||||
|
|
||||||
RenderObject obj{};
|
RenderObject obj{};
|
||||||
obj.indexCount = surf.count;
|
obj.indexCount = _earth_patch_index_count;
|
||||||
obj.firstIndex = surf.startIndex;
|
obj.firstIndex = 0;
|
||||||
obj.indexBuffer = mesh->meshBuffers.indexBuffer.buffer;
|
obj.indexBuffer = _earth_patch_index_buffer.buffer;
|
||||||
obj.vertexBuffer = mesh->meshBuffers.vertexBuffer.buffer;
|
obj.vertexBuffer = patch->vertex_buffer.buffer;
|
||||||
obj.vertexBufferAddress = mesh->meshBuffers.vertexBufferAddress;
|
obj.vertexBufferAddress = patch->vertex_buffer_address;
|
||||||
obj.material = surf.material ? &surf.material->data : nullptr;
|
obj.material = earth->material ? &earth->material->data : nullptr;
|
||||||
obj.bounds = surf.bounds;
|
obj.bounds = b;
|
||||||
obj.transform = transform;
|
obj.transform = transform;
|
||||||
// Planet terrain patches are not meaningful RT occluders; skip BLAS/TLAS builds.
|
// Planet terrain patches are not meaningful RT occluders; skip BLAS/TLAS builds.
|
||||||
obj.sourceMesh = nullptr;
|
obj.sourceMesh = nullptr;
|
||||||
obj.surfaceIndex = surface_index++;
|
obj.surfaceIndex = 0;
|
||||||
obj.objectID = draw_context.nextID++;
|
obj.objectID = draw_context.nextID++;
|
||||||
obj.ownerType = RenderObject::OwnerType::MeshInstance;
|
obj.ownerType = RenderObject::OwnerType::MeshInstance;
|
||||||
obj.ownerName = earth->name;
|
obj.ownerName = earth->name;
|
||||||
|
|
||||||
draw_context.OpaqueSurfaces.push_back(obj);
|
draw_context.OpaqueSurfaces.push_back(obj);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
const Clock::time_point t_emit1 = Clock::now();
|
const Clock::time_point t_emit1 = Clock::now();
|
||||||
|
|
||||||
trim_earth_patch_cache();
|
trim_earth_patch_cache();
|
||||||
@@ -333,7 +533,7 @@ void PlanetSystem::update_and_emit(const SceneManager &scene, DrawContext &draw_
|
|||||||
_earth_debug_stats.quadtree = _earth_quadtree.stats();
|
_earth_debug_stats.quadtree = _earth_quadtree.stats();
|
||||||
_earth_debug_stats.visible_patches = visible_patches;
|
_earth_debug_stats.visible_patches = visible_patches;
|
||||||
_earth_debug_stats.created_patches = created_patches;
|
_earth_debug_stats.created_patches = created_patches;
|
||||||
_earth_debug_stats.patch_cache_size = static_cast<uint32_t>(_earth_patch_cache.size());
|
_earth_debug_stats.patch_cache_size = static_cast<uint32_t>(_earth_patch_lookup.size());
|
||||||
_earth_debug_stats.estimated_triangles = estimated_tris;
|
_earth_debug_stats.estimated_triangles = estimated_tris;
|
||||||
_earth_debug_stats.ms_quadtree = static_cast<float>(std::chrono::duration<double, std::milli>(t_q1 - t_q0).count());
|
_earth_debug_stats.ms_quadtree = static_cast<float>(std::chrono::duration<double, std::milli>(t_q1 - t_q0).count());
|
||||||
_earth_debug_stats.ms_patch_create = static_cast<float>(ms_patch_create);
|
_earth_debug_stats.ms_patch_create = static_cast<float>(ms_patch_create);
|
||||||
|
|||||||
@@ -74,16 +74,35 @@ public:
|
|||||||
void set_earth_patch_cache_max(uint32_t max_patches) { _earth_patch_cache_max = max_patches; }
|
void set_earth_patch_cache_max(uint32_t max_patches) { _earth_patch_cache_max = max_patches; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct EarthPatchCacheEntry
|
enum class EarthPatchState : uint8_t
|
||||||
{
|
{
|
||||||
std::shared_ptr<MeshAsset> mesh;
|
Allocating = 0,
|
||||||
|
Ready = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EarthPatch
|
||||||
|
{
|
||||||
|
planet::PatchKey key{};
|
||||||
|
EarthPatchState state = EarthPatchState::Allocating;
|
||||||
|
|
||||||
|
AllocatedBuffer vertex_buffer{};
|
||||||
|
VkDeviceAddress vertex_buffer_address = 0;
|
||||||
|
|
||||||
|
glm::vec3 bounds_origin{0.0f};
|
||||||
|
glm::vec3 bounds_extents{0.5f};
|
||||||
|
float bounds_sphere_radius = 0.5f;
|
||||||
|
|
||||||
WorldVec3 patch_center_dir{0.0, 0.0, 1.0};
|
WorldVec3 patch_center_dir{0.0, 0.0, 1.0};
|
||||||
uint32_t last_used_frame = 0;
|
uint32_t last_used_frame = 0;
|
||||||
std::list<planet::PatchKey>::iterator lru_it;
|
std::list<uint32_t>::iterator lru_it{};
|
||||||
};
|
};
|
||||||
|
|
||||||
void ensure_bodies_created();
|
void ensure_bodies_created();
|
||||||
std::shared_ptr<MeshAsset> get_or_create_earth_patch_mesh(const PlanetBody &earth, const planet::PatchKey &key);
|
EarthPatch *find_earth_patch(const planet::PatchKey &key);
|
||||||
|
EarthPatch *get_or_create_earth_patch(const PlanetBody &earth,
|
||||||
|
const planet::PatchKey &key,
|
||||||
|
uint32_t frame_index);
|
||||||
|
void ensure_earth_patch_index_buffer();
|
||||||
void trim_earth_patch_cache();
|
void trim_earth_patch_cache();
|
||||||
|
|
||||||
EngineContext *_context = nullptr;
|
EngineContext *_context = nullptr;
|
||||||
@@ -94,8 +113,14 @@ private:
|
|||||||
planet::PlanetQuadtree _earth_quadtree{};
|
planet::PlanetQuadtree _earth_quadtree{};
|
||||||
planet::PlanetQuadtree::Settings _earth_quadtree_settings{};
|
planet::PlanetQuadtree::Settings _earth_quadtree_settings{};
|
||||||
EarthDebugStats _earth_debug_stats{};
|
EarthDebugStats _earth_debug_stats{};
|
||||||
std::unordered_map<planet::PatchKey, EarthPatchCacheEntry, planet::PatchKeyHash> _earth_patch_cache;
|
std::unordered_map<planet::PatchKey, uint32_t, planet::PatchKeyHash> _earth_patch_lookup;
|
||||||
std::list<planet::PatchKey> _earth_patch_lru;
|
std::vector<EarthPatch> _earth_patches;
|
||||||
|
std::vector<uint32_t> _earth_patch_free;
|
||||||
|
std::list<uint32_t> _earth_patch_lru;
|
||||||
|
AllocatedBuffer _earth_patch_index_buffer{};
|
||||||
|
uint32_t _earth_patch_index_count = 0;
|
||||||
|
uint32_t _earth_patch_index_resolution = 0;
|
||||||
|
uint32_t _earth_patch_frame_stamp = 0;
|
||||||
uint32_t _earth_patch_resolution = 33;
|
uint32_t _earth_patch_resolution = 33;
|
||||||
uint32_t _earth_patch_create_budget_per_frame = 16;
|
uint32_t _earth_patch_create_budget_per_frame = 16;
|
||||||
float _earth_patch_create_budget_ms = 2.0f;
|
float _earth_patch_create_budget_ms = 2.0f;
|
||||||
|
|||||||
Reference in New Issue
Block a user