Commit f3c70601 authored by Shu's avatar Shu 🍠
Browse files

DualMC

parent 079888cf
......@@ -3,7 +3,7 @@
## Data
- [x] Generate noise
- [x] Density
- [ ] Robin hood map / hopscotch_map
- [x] Robin hood map
- [ ] Octree world
- [ ] Serialize
- [ ] In memory RLE
......@@ -19,7 +19,7 @@
- https://speciesdevblog.files.wordpress.com/2012/11/biomemap.png
- [ ] Leak test
- Valgrind
- Massif
- Xtree-memory
- [ ] Server
- [ ] ZeroMQ
......@@ -48,10 +48,11 @@
- [x] Box contouring
- [x] Ignore sides
- [ ] LOD
- [ ] Dual MC
- [x] Dual MC
- [ ] Octree
- [ ] Collision
- [ ] Dynamic index size
- [ ] Chunk size performance
- [x] Chunk size performance
- [ ] Render with glBufferSubData
- [x] Frustum Culling
- [ ] Occlusion Culling
......
......@@ -10,9 +10,19 @@ uniform sampler2DArray HOSAtlas;
uniform mat4 View;
uniform vec3 FogColor;
in VertexData {
#ifdef BLEND
in GeometryData
#else
in VertexData
#endif
{
vec3 Position_worldspace;
float Material;
#ifdef BLEND
flat uint Materials[3];
vec3 MaterialRatio;
#else
flat uint Material;
#endif
vec3 FaceNormal_modelspace;
#ifdef PBR
vec3 FaceNormal_worldspace;
......@@ -30,9 +40,9 @@ vec3 expand(vec3 v) {
vec4 getTexture(sampler2DArray sample, vec2 UV) {
#ifdef BLEND
vec4 colx = texture(sample, vec3(UV, vs.Materials.x));
vec4 coly = texture(sample, vec3(UV, vs.Materials.y));
vec4 colz = texture(sample, vec3(UV, vs.Materials.z));
vec4 colx = texture(sample, vec3(UV, vs.Materials[0]));
vec4 coly = texture(sample, vec3(UV, vs.Materials[1]));
vec4 colz = texture(sample, vec3(UV, vs.Materials[2]));
return colx * vs.MaterialRatio.x + coly * vs.MaterialRatio.y + colz * vs.MaterialRatio.z;
#else
return texture(sample, vec3(UV, vs.Material));
......
#version 330 core
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
in VertexData {
vec3 Position_worldspace;
flat uint Material;
vec3 FaceNormal_modelspace;
#ifdef PBR
vec3 FaceNormal_worldspace;
vec3 EyeDirection_cameraspace;
vec3 LightDirection_cameraspace;
#endif
#ifdef FOG
float Depth;
#endif
} vs_in[];
out GeometryData {
vec3 Position_worldspace;
flat uint Materials[3];
vec3 MaterialRatio;
vec3 FaceNormal_modelspace;
#ifdef PBR
vec3 FaceNormal_worldspace;
vec3 EyeDirection_cameraspace;
vec3 LightDirection_cameraspace;
#endif
#ifdef FOG
float Depth;
#endif
} gs;
void main() {
for(int i = 0; i < gl_in.length(); i++) {
gl_Position = gl_in[i].gl_Position;
gs.Position_worldspace = vs_in[i].Position_worldspace;
gs.FaceNormal_modelspace = vs_in[i].FaceNormal_modelspace;
gs.FaceNormal_worldspace = vs_in[i].FaceNormal_worldspace;
gs.Materials[i] = vs_in[i].Material;
switch(int(mod(i,3))) {
case 0:
gs.MaterialRatio = vec3(1,0,0);
break;
case 1:
gs.MaterialRatio = vec3(0,1,0);
break;
case 2:
gs.MaterialRatio = vec3(0,0,1);
break;
default:
gs.MaterialRatio = vec3(0);
break;
};
gs.EyeDirection_cameraspace = vs_in[i].EyeDirection_cameraspace;
gs.LightDirection_cameraspace = vs_in[i].LightDirection_cameraspace;
#ifdef SHADOW
gs.ShadowCoord = vs_in[i].ShadowCoord;
#endif
#ifdef FOG
gs.Depth = vs_in[i].Depth;
#endif
EmitVertex();
}
EndPrimitive();
}
\ No newline at end of file
......@@ -6,7 +6,7 @@ layout(location = 2) in vec3 Normal_modelspace;
out VertexData {
vec3 Position_worldspace;
float Material;
flat uint Material;
vec3 FaceNormal_modelspace;
#ifdef PBR
vec3 FaceNormal_worldspace;
......@@ -33,7 +33,7 @@ void main(){
vs.Depth = length((View * vec4(vs.Position_worldspace,1)).xyz) / FogDepth;
#endif
vs.Material = float(Material_model);
vs.Material = Material_model;
vs.FaceNormal_modelspace = normalize(Normal_modelspace);
#ifdef PBR
......
This diff is collapsed.
#include "FlatDualMC.hpp"
#include "../world/Chunk.hpp"
#include "../world/materials.hpp"
#include <Remotery.h>
#include <imgui.h>
#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<chunk_pos, surrounding::corners> ctx;
loadQueue.wait();
if (loadQueue.pop(ctx)) {
rmt_ScopedCPUSample(ProcessContouring, 0);
ShortIndexedBuffer::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<chunk_pos, std::shared_ptr<Chunk>> &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<chunk_pos, std::shared_ptr<Chunk>> &data, Faces neighbors) {
enqueue(pos, data);
if (neighbors && (Faces::Left | Faces::Down | 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<chunk_pos, std::shared_ptr<Chunk>> &data) {
if (buffers.find(pos) == buffers.end()) {
enqueue(pos, data);
}
}
void FlatDualMC::update(const camera_pos& pos) {
AbstractFlat::update(pos);
std::pair<chunk_pos, ShortIndexedBuffer::Data> 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 ShortIndexedBuffer(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, ShortIndexedBuffer::Data &out) const {
const int SIZE = CHUNK_LENGTH + 3;
std::vector<dualmc::DualMC<float>::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->get(Chunk::getIdx(x % CHUNK_LENGTH, y % CHUNK_LENGTH, z % CHUNK_LENGTH));
grid.push_back({voxel.Density * 1.f / UCHAR_MAX, voxel.Material});
}}}
}
{
std::vector<dualmc::Vertex> dmc_vertices;
std::vector<dualmc::Tri> dmc_tris;
dualmc::DualMC<float> builder;
builder.buildTris(&grid.front(), SIZE, SIZE, SIZE, iso, 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);
}
}
}
}
#pragma once
#include "AbstractFlat.hpp"
#include "surrounding.hpp"
#include "../data/safe_queue.hpp"
#include "../data/safe_priority_queue.hpp"
#include "../data/circular_buffer.hpp"
#include "../render/buffer/ShortIndexedBuffer.hpp"
#include <thread>
#define REPORT_BUFFER_SIZE 128
namespace contouring {
class FlatDualMC: public AbstractFlat {
public:
FlatDualMC(const std::string&);
virtual ~FlatDualMC();
void update(const camera_pos&) override;
void onGui() override;
std::string getOptions() override;
/// Chunk data change
void onUpdate(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &, Faces) override;
/// Chunk existante ping
/// @note notify for chunks entering view while moving
void onNotify(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &) override;
protected:
safe_priority_queue_map<chunk_pos, surrounding::corners, int> loadQueue;
safe_queue<std::pair<chunk_pos, ShortIndexedBuffer::Data>> loadedQueue;
struct report {
circular_buffer<float> count = circular_buffer<float>(REPORT_BUFFER_SIZE, 0); // MAYBE: store int
circular_buffer<float> load = circular_buffer<float>(REPORT_BUFFER_SIZE, 0);
circular_buffer<float> loaded = circular_buffer<float>(REPORT_BUFFER_SIZE, 0);
} reports;
bool running = true;
std::vector<std::thread> workers;
void enqueue(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &);
float iso = .1f;
bool manifold = true;
void render(const surrounding::corners &surrounding, ShortIndexedBuffer::Data& out) const;
};
}
......@@ -10,7 +10,7 @@ namespace contouring {
for (size_t i = 1; i <= 4; i++) {
workers.push_back(std::thread([&] {
while (running) {
std::pair<chunk_pos, surrounding::chunks> ctx;
std::pair<chunk_pos, surrounding::faces> ctx;
loadQueue.wait();
if (loadQueue.pop(ctx)) {
rmt_ScopedCPUSample(ProcessContouring, 0);
......@@ -39,7 +39,7 @@ namespace contouring {
rmt_ScopedCPUSample(EnqueueContouring, RMTSF_Aggregate);
const auto dist2 = glm::length2(pos - center);
if (dist2 <= loadDistance * loadDistance) {
surrounding::chunks surrounding;
surrounding::faces surrounding;
if(surrounding::load(surrounding, pos, data)) {
loadQueue.push(pos, surrounding, -dist2);
}
......@@ -102,11 +102,11 @@ namespace contouring {
AbstractFlat::onGui();
}
bool FlatSurroundingBox::isTransparent(const surrounding::chunks &surrounding, const std::pair<ushort, ushort> &idx) {
bool FlatSurroundingBox::isTransparent(const surrounding::faces &surrounding, const std::pair<ushort, ushort> &idx) {
return surrounding[idx.first]->begin()[idx.second].Density < UCHAR_MAX; // MAYBE: materials::transparent
}
void FlatSurroundingBox::render(const surrounding::chunks &surrounding, std::vector<VertexData> &vertices) {
void FlatSurroundingBox::render(const surrounding::faces &surrounding, std::vector<VertexData> &vertices) {
const auto voxels = surrounding[surrounding::CENTER]->begin();
vertices.clear();
for (ushort i = 0; i < CHUNK_SIZE; i++) {
......
......@@ -28,7 +28,7 @@ namespace contouring {
void onNotify(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &) override;
protected:
safe_priority_queue_map<chunk_pos, surrounding::chunks, int> loadQueue;
safe_priority_queue_map<chunk_pos, surrounding::faces, int> loadQueue;
safe_queue<std::pair<chunk_pos, ShortIndexedBuffer::Data>> loadedQueue;
struct report {
......@@ -43,7 +43,7 @@ namespace contouring {
void enqueue(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &);
private:
static inline bool isTransparent(const surrounding::chunks &surrounding, const std::pair<ushort, ushort> &idx);
static void render(const surrounding::chunks &surrounding, std::vector<VertexData> &vertices);
static inline bool isTransparent(const surrounding::faces &surrounding, const std::pair<ushort, ushort> &idx);
static void render(const surrounding::faces &surrounding, std::vector<VertexData> &vertices);
};
}
This diff is collapsed.
#include "index.hpp"
#include "Dummy.hpp"
#include "FlatSurroundingBox.hpp"
#include "FlatDualMC.hpp"
namespace contouring {
int idxByName(const std::string& name) {
......@@ -13,11 +14,14 @@ namespace contouring {
std::shared_ptr<Abstract> load(int idx, const std::map<std::string, std::string>& data) {
switch (idx) {
case 1:
case 2:
return std::make_shared<Dummy>();
case 1:
return std::make_shared<FlatSurroundingBox>(data.at(names[1]));
default:
return std::make_shared<FlatSurroundingBox>(data.at(names[0]));
return std::make_shared<FlatDualMC>(data.at(names[0]));
}
}
void save(int idx, std::shared_ptr<Abstract>& ct, std::map<std::string, std::string>& data) {
......
......@@ -3,8 +3,8 @@
#include "Abstract.hpp"
namespace contouring {
static const std::array<std::string, 2> names = {"FlatBox", "Dummy"};
static const std::string cnames = "FlatBox\0Dummy\0";
static const std::array<std::string, 3> names = {"FlatDualMC", "FlatBox", "Dummy"};
static const char* cnames = "FlatDualMC\0FlatBox\0Dummy\0";
int idxByName(const std::string &name);
std::shared_ptr<Abstract> load(int idx, const std::map<std::string, std::string> &data);
......
......@@ -3,7 +3,7 @@
#include "../world/Chunk.hpp"
namespace contouring::surrounding {
bool load(chunks &out, const chunk_pos &chunkPos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &chunks) {
bool load(faces &out, const chunk_pos &chunkPos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &chunks) {
{
const auto it = chunks.find(chunkPos);
if (it == chunks.end())
......@@ -57,4 +57,15 @@ namespace contouring::surrounding {
return {CENTER, idx};
}
}
bool load(corners &out, const chunk_pos &chunkPos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &chunks) {
for (size_t i = 0; i < 8; i++) {
const auto it = chunks.find(chunkPos + g_corner_offsets[i]);
if (it == chunks.end())
return false;
out[i] = it->second;
}
return true;
}
}
......@@ -7,9 +7,23 @@
class Chunk;
namespace contouring::surrounding {
const auto CENTER = 6;
typedef std::array<std::shared_ptr<const Chunk>, CENTER+1> chunks;
typedef std::array<std::shared_ptr<const Chunk>, CENTER+1> faces;
bool load(chunks &out, const chunk_pos &chunkPos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &chunks);
bool load(faces &out, const chunk_pos &chunkPos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &chunks);
std::pair<ushort, ushort> getNeighborIdx(ushort idx, Face face);
typedef std::array<std::shared_ptr<const Chunk>, 8> corners;
const glm::ivec3 g_corner_offsets[8] = {
glm::ivec3(0, 0, 0),
glm::ivec3(0, 0, 1),
glm::ivec3(0, 1, 0),
glm::ivec3(0, 1, 1),
glm::ivec3(1, 0, 0),
glm::ivec3(1, 0, 1),
glm::ivec3(1, 1, 0),
glm::ivec3(1, 1, 1),
};
bool load(corners &out, const chunk_pos &chunkPos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &chunks);
}
......@@ -40,6 +40,7 @@ struct options {
renderer.mipMapLOD = config["render"]["texture_quality"].value_or(renderer.mipMapLOD);
renderer.main.pbr = config["render"]["pbr"].value_or(renderer.main.pbr);
renderer.main.triplanar = config["render"]["triplanar"].value_or(renderer.main.triplanar);
renderer.main.blend = config["render"]["blend"].value_or(renderer.main.blend);
renderer.main.fog = config["render"]["fog"].value_or(renderer.main.fog);
const std::string fog = config["render"]["fog_color"].value_or(std::string{"#000000"});
renderer.clear_color = fromHex(fog);
......@@ -83,6 +84,7 @@ struct options {
{"texture_quality", renderer.mipMapLOD},
{"pbr", renderer.main.pbr},
{"triplanar", renderer.main.triplanar},
{"blend", renderer.main.blend},
{"fog", renderer.main.fog},
{"fog_color", toHexa(renderer.clear_color)},
{"skybox", renderer.skybox}
......
......@@ -128,11 +128,11 @@ int main(int, char *[]){
pass.start();
std::vector<std::pair<glm::mat4, Buffer *const>> models;
std::optional<Frustum> furstum;
std::optional<Frustum> frustum;
if(options.culling) {
furstum = {camera.getFrustum()};
frustum = {camera.getFrustum()};
}
world.getContouring()->getModels(models, camera.getFrustum(), options.voxel_size);
world.getContouring()->getModels(models, frustum, options.voxel_size);
reports.main.models_count = 0;
reports.main.tris_count = 0;
rmt_ScopedOpenGLSample(Render);
......
......@@ -67,15 +67,14 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
if (ImGui::Checkbox("Fullscreen", &options.fullscreen)){
actions = actions | Actions::FullScreen;
}
if (ImGui::ColorEdit3("Fog color", (float *)&options.renderer.clear_color)) {
actions = actions | Actions::ClearColor;
}
{
bool changeRenderer = false;
changeRenderer |= ImGui::Checkbox("PBR", &options.renderer.main.pbr);
ImGui::SameLine();
changeRenderer |= ImGui::Checkbox("Triplanar", &options.renderer.main.triplanar);
ImGui::SameLine();
changeRenderer |= ImGui::Checkbox("Blend", &options.renderer.main.blend);
changeRenderer |= ImGui::Checkbox("Fog", &options.renderer.main.fog);
ImGui::SameLine();
......@@ -84,6 +83,9 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
actions = actions | Actions::RendererSharders;
}
}
if (ImGui::ColorEdit3("Fog color", (float *)&options.renderer.clear_color)) {
actions = actions | Actions::ClearColor;
}
if (ImGui::Checkbox("Wireframe", &options.renderer.wireframe))
glPolygonMode(GL_FRONT_AND_BACK, options.renderer.wireframe ? GL_LINE : GL_FILL);
ImGui::Text("Textures '%s'", options.renderer.textures.c_str()); // MAYBE: select
......@@ -115,7 +117,7 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
if (options.show_debug_contouring) {
ImGui::Begin("Debug: Contouring", &options.show_debug_contouring, ImGuiWindowFlags_AlwaysAutoResize);
const auto prev_idx = options.contouring_idx;
if(ImGui::Combo("Contouring", &options.contouring_idx, contouring::cnames.c_str())) {
if(ImGui::Combo("Contouring", &options.contouring_idx, contouring::cnames)) {
actions = actions | Actions::ChangeContouring;
contouring::save(prev_idx, state.contouring, options.contouring_data);
}
......
......@@ -11,10 +11,14 @@ MainProgram::MainProgram(const MainProgram::options& opts): Program() {
flags.push_back("TRIPLANAR");
if (opts.fog)
flags.push_back("FOG");
if (opts.blend)
flags.push_back("BLEND");