#include "FlatDualMC.hpp" #include "../world/Chunk.hpp" #include "../world/materials.hpp" #include #include #include "dualmc.h" namespace contouring { FlatDualMC::FlatDualMC(const std::string &str) : AbstractFlat(str) { auto opt = toml::parse(str); iso = opt["iso"].value_or(iso); manifold = opt["manifold"].value_or(manifold); for (size_t i = 1; i <= 2; i++) { workers.push_back(std::thread([&] { while (running) { std::pair ctx; loadQueue.wait(); if (loadQueue.pop(ctx)) { rmt_ScopedCPUSample(ProcessContouring, 0); buffer::ShortIndexed::Data data; render(ctx.second, data); loadedQueue.push({ctx.first, data}); } } })); } } FlatDualMC::~FlatDualMC() { running = false; loadQueue.notify(); for(auto& worker: workers) { if (worker.joinable()) worker.join(); } } std::string FlatDualMC::getOptions() { std::ostringstream ss; ss << toml::table({ {"load_distance", loadDistance}, {"keep_distance", keepDistance}, {"iso", iso}, {"manifold", manifold} }); return ss.str(); } void FlatDualMC::enqueue(const chunk_pos &pos, const robin_hood::unordered_map> &data) { rmt_ScopedCPUSample(EnqueueContouring, RMTSF_Aggregate); const auto dist2 = glm::length2(pos - center); if (dist2 <= loadDistance * loadDistance) { surrounding::corners surrounding; if(surrounding::load(surrounding, pos, data)) { loadQueue.push(pos, surrounding, -dist2); } } } void FlatDualMC::onUpdate(const chunk_pos &pos, const robin_hood::unordered_map> &data, geometry::Faces neighbors) { enqueue(pos, data); if (neighbors && (geometry::Faces::Left | geometry::Faces::Down | geometry::Faces::Backward)) { for (size_t i = 1; i < 8; i++) { enqueue(pos - surrounding::g_corner_offsets[i], data); } } } void FlatDualMC::onNotify(const chunk_pos &pos, const robin_hood::unordered_map> &data) { if (buffers.find(pos) == buffers.end()) { enqueue(pos, data); } } void FlatDualMC::update(const camera_pos& pos) { AbstractFlat::update(pos); std::pair out; reports.load.push(loadQueue.size()); //MAYBE: clear out of range loadQueue.trim(keepDistance * keepDistance) reports.loaded.push(loadedQueue.size()); while(loadedQueue.pop(out)) { const auto buffer = new buffer::ShortIndexed(GL_TRIANGLES, out.second); const auto it = buffers.find(out.first); if (it != buffers.end()) { if(it->second != NULL) delete it->second; it->second = buffer; } else { buffers.emplace(out.first, buffer); } } reports.count.push(buffers.size()); } void FlatDualMC::onGui() { ImGui::PlotHistogram("Count", reports.count.buffer.get(), reports.count.size, 0, std::to_string(reports.count.current()).c_str(), 0); ImGui::PlotHistogram("Loading", reports.load.buffer.get(), reports.load.size, 0, std::to_string(reports.load.current()).c_str(), 0); ImGui::PlotHistogram("Waiting", reports.loaded.buffer.get(), reports.loaded.size, 0, std::to_string(reports.loaded.current()).c_str(), 0); ImGui::Separator(); AbstractFlat::onGui(); ImGui::Separator(); ImGui::SliderFloat("Iso", &iso, 0, 1); ImGui::Checkbox("Manifold", &manifold); } void FlatDualMC::render(const surrounding::corners &surrounding, buffer::ShortIndexed::Data &out) const { const int SIZE = CHUNK_LENGTH + 3; std::vector::Point> grid; grid.reserve(SIZE * SIZE * SIZE); { for (int z = 0; z < SIZE; z++) { for (int y = 0; y < SIZE; y++) { for (int x = 0; x < SIZE; x++) { const auto chunk = surrounding[(z >= CHUNK_LENGTH) + (y >= CHUNK_LENGTH)*2 + (x >= CHUNK_LENGTH)*4]; // MAYBE: area copy const auto voxel = chunk->getAt(chunk_voxel_pos(x % CHUNK_LENGTH, y % CHUNK_LENGTH, z % CHUNK_LENGTH)); grid.push_back({voxel.Density * 1.f / UCHAR_MAX, voxel.Material}); }}} } { std::vector dmc_vertices; std::vector dmc_tris; dualmc::DualMC builder; builder.buildTris(&grid.front(), SIZE, SIZE, SIZE, iso, world::materials::roughness.cbegin(), manifold, dmc_vertices, dmc_tris); out.vertices.reserve(dmc_vertices.size()); out.materials.reserve(dmc_vertices.size()); out.normals.reserve(dmc_vertices.size()); for (const auto& v: dmc_vertices) { out.vertices.push_back(glm::vec3(v.x, v.y, v.z)); out.materials.push_back(v.w); out.normals.push_back(glm::vec3(0)); } out.indices.reserve(dmc_tris.size()); for (const auto& t: dmc_tris) { out.indices.push_back(t.i0); out.indices.push_back(t.i1); out.indices.push_back(t.i2); glm::vec3 edge1 = out.vertices[t.i1] - out.vertices[t.i0]; glm::vec3 edge2 = out.vertices[t.i2] - out.vertices[t.i0]; glm::vec3 normal = glm::normalize(glm::cross(edge1, edge2)); out.normals[t.i0] += normal; out.normals[t.i1] += normal; out.normals[t.i2] += normal; } for (auto &n : out.normals) { n = glm::normalize(n); } } } }