From 53fe3104db5c6e43d7f43503126fde920a003db7 Mon Sep 17 00:00:00 2001 From: David Allemang Date: Fri, 10 Feb 2023 13:20:34 -0500 Subject: [PATCH] ENH: Dynamically enable and color tilings Use multidraw and command buffer --- vis/include/cgl/buffer.hpp | 20 +++--- vis/include/solver.hpp | 60 ++++++++++++---- vis/shaders/deferred.vs.glsl | 4 +- vis/shaders/slice.gm.glsl | 4 +- vis/shaders/solid.fs.glsl | 3 +- vis/src/comps.hpp | 132 ++++++++++++++++++++++------------- vis/src/main.cpp | 52 ++++++++++---- 7 files changed, 185 insertions(+), 90 deletions(-) diff --git a/vis/include/cgl/buffer.hpp b/vis/include/cgl/buffer.hpp index e43e14f..9aff575 100644 --- a/vis/include/cgl/buffer.hpp +++ b/vis/include/cgl/buffer.hpp @@ -8,6 +8,7 @@ namespace cgl { template class Buffer { GLuint id{}; + size_t _count = 0; public: using Element = T; @@ -32,25 +33,26 @@ namespace cgl { } [[nodiscard]] size_t size() const { - GLint res; - glGetNamedBufferParameteriv(id, GL_BUFFER_SIZE, &res); - return (size_t) res; + return _count * sizeof(T); } [[nodiscard]] size_t count() const { - return size() / sizeof(T); - } - - void put(const T &data, GLenum usage = GL_STATIC_DRAW) { - glNamedBufferData(id, sizeof(T), &data, usage); + return _count; } template void put(It begin, It end, GLenum usage = GL_STATIC_DRAW) { - glNamedBufferData(id, sizeof(T) * (end - begin), nullptr, usage); + _count = end - begin; + + glNamedBufferData(id, sizeof(T) * _count, nullptr, usage); void* ptr = glMapNamedBuffer(id, GL_WRITE_ONLY); std::copy(begin, end, (T*) ptr); glUnmapNamedBuffer(id); } + + void put(const T &data, GLenum usage = GL_STATIC_DRAW) { + T const* ptr = &data; + put(ptr, ptr + 1, usage); + } }; } diff --git a/vis/include/solver.hpp b/vis/include/solver.hpp index 67e1e4a..9e61f97 100644 --- a/vis/include/solver.hpp +++ b/vis/include/solver.hpp @@ -112,7 +112,7 @@ Indices cell( std::vector> facets; - for (auto H : G.subs(N - 2)) { + for (auto H: G.subs(N - 2)) { auto sub_base = cell(H); auto base = recontext(sub_base, G, H); auto tiles = tile(base, G, H); @@ -140,17 +140,53 @@ Indices<1> cell<1>( } template -auto hull( - const tc::Group &G -) { - std::vector> parts; +struct Hull { + struct Tiling { + Eigen::Index first; + Eigen::Index count; + }; - for (auto H: G.subs(N - 1)) { - auto sub_base = cell(H); - auto base = recontext(sub_base, G, H); - auto tiles = tile(base, G, H); - parts.push_back(merge(tiles)); + std::vector tilings{}; + std::vector> subgroups{}; + + Indices inds{}; + + explicit Hull(tc::Group const &G) { + std::vector> parts; + + Eigen::Index first = 0; + for (const auto &H: G.subs(N - 1)) { + auto sub_base = cell(H); + auto base = recontext(sub_base, G, H); + auto tiles = tile(base, G, H); + auto tiling = merge(tiles); + + subgroups.push_back(H.gens()); + tilings.push_back({first, tiling.cols()}); + + parts.push_back(tiling); + first += tiling.cols(); + } + + inds = merge(parts); } +}; - return parts; -} +struct Points { + Eigen::Array verts; + + explicit Points(tc::Group const &G, Eigen::Vector root) { + auto mirrors = mirror<5>(G); + auto corners = plane_intersections(mirrors); + + auto start = corners * root; + + tc::Cosets table = G.solve(); + tc::Path path(table, mirrors.colwise()); + + Eigen::Array higher(5, path.order()); + path.walk(start, Reflect(), higher.matrix().colwise().begin()); + + verts = Stereo()(higher); + } +}; diff --git a/vis/shaders/deferred.vs.glsl b/vis/shaders/deferred.vs.glsl index fe7cf77..9bd01d2 100644 --- a/vis/shaders/deferred.vs.glsl +++ b/vis/shaders/deferred.vs.glsl @@ -15,10 +15,10 @@ layout(std140, binding=2) uniform ModelMatrices { }; layout(location=0) in ivec4 inds; -layout(location=1) in vec4 col; +layout(location=1) in vec3 col; out ivec4 vInds; -out vec4 vCol; +out vec3 vCol; out gl_PerVertex { vec4 gl_Position; diff --git a/vis/shaders/slice.gm.glsl b/vis/shaders/slice.gm.glsl index 69c56bf..3c96841 100644 --- a/vis/shaders/slice.gm.glsl +++ b/vis/shaders/slice.gm.glsl @@ -18,10 +18,10 @@ layout(std140, binding=2) uniform ModelMatrices { }; in ivec4 vInds[]; -in vec4 vCol[]; +in vec3 vCol[]; layout(location=0) out vec4 pos; -layout(location=1) out vec4 col; +layout(location=1) out vec3 col; layout(location=2) out vec3 normal; out gl_PerVertex { diff --git a/vis/shaders/solid.fs.glsl b/vis/shaders/solid.fs.glsl index 232d04a..7d10dd0 100644 --- a/vis/shaders/solid.fs.glsl +++ b/vis/shaders/solid.fs.glsl @@ -1,8 +1,7 @@ #version 430 -layout(location=2) uniform vec3 col; - layout(location=0) in vec3 pos; +layout(location=1) in vec3 col; layout(location=2) in vec3 normal; out vec4 color; diff --git a/vis/src/comps.hpp b/vis/src/comps.hpp index 68c4d9b..82f4470 100644 --- a/vis/src/comps.hpp +++ b/vis/src/comps.hpp @@ -18,65 +18,93 @@ #include namespace vis { - struct Group { - tc::Group group; - vec5 root; - vec3 color; + template + struct Structure { + using Affine4f = Eigen::Transform; + + using Vertex = Eigen::Vector; + using Color = Eigen::Vector; + using Cell = Eigen::Array; + + Points points; + Hull hull; + + std::vector enabled; + std::vector colors; + + Affine4f transform = Affine4f::Identity(); + + template + explicit Structure(P &&points_, H &&hull_, Color color_ = Color::Ones()): + points(std::forward

(points_)), + hull(std::forward(hull_)), + enabled(hull.tilings.size(), true), + colors(hull.tilings.size(), color_), + transform(Affine4f::Identity()) { + + } }; struct VBOs { - struct ModelMatrix { + struct Uniform { Eigen::Matrix4f linear; Eigen::Vector4f translation; }; - cgl::Buffer verts; - cgl::Buffer> ibo; - cgl::Buffer ubo; + struct Command { + unsigned int count, instanceCount, first, baseInstance; + }; - using Affine4f = Eigen::Transform; - - Affine4f tform = Affine4f::Identity(); + cgl::Buffer::Vertex> vertices; + cgl::Buffer::Color> colors; + cgl::Buffer::Cell> indices; + cgl::Buffer uniform; + cgl::Buffer commands; }; - void upload_groups(entt::registry ®) { - auto view = reg.view(); + void upload_structure(entt::registry ®istry) { + auto view = registry.view, VBOs>(); - for (auto [entity, group, vbos]: view.each()) { - auto cosets = group.group.solve(); - auto mirrors = mirror<5>(group.group); - auto corners = plane_intersections(mirrors); + for (auto [entity, structure, vbos]: view.each()) { + auto vertices = structure.points.verts.colwise(); + auto indices = structure.hull.inds.colwise(); - vec5 start = corners * group.root; - - tc::Path path(cosets, mirrors.colwise()); - - Eigen::Array higher(5, path.order()); - path.walk(start, Reflect(), higher.matrix().colwise().begin()); - - Eigen::Array lower = Stereo()(higher); - - vbos.verts.put(lower.colwise().begin(), lower.colwise().end()); - - // todo generate all, then mask using glMultiDraw. - const Eigen::Index N = 4; - - auto tiles = hull(group.group); - - tiles.erase(tiles.begin()); // remove {0, 1, 2} cells - - auto inds = merge(tiles); - - vbos.ibo.put(inds.colwise().begin(), inds.colwise().end()); + vbos.vertices.put(vertices.begin(), vertices.end()); + vbos.indices.put(indices.begin(), indices.end()); } } - void upload_ubo(entt::registry ®) { - auto view = reg.view(); + void upload_uniforms(entt::registry ®istry) { + auto view = registry.view, VBOs>(); - for (auto [entity, vbos]: view.each()) { - vbos.ubo.put({vbos.tform.linear(), - vbos.tform.translation()}); + for (auto [entity, structure, vbos]: view.each()) { + auto colors = structure.colors; + VBOs::Uniform uniform{ + structure.transform.linear(), + structure.transform.translation(), + }; + + vbos.colors.put(colors.begin(), colors.end()); + vbos.uniform.put(uniform, GL_STREAM_DRAW); + } + } + + void upload_commands(entt::registry ®istry) { + auto view = registry.view, VBOs>(); + + for (auto [entity, structure, vbos]: view.each()) { + const auto &tilings = structure.hull.tilings; + + std::vector commands; + + for (unsigned int i = 0; i < tilings.size(); ++i) { + if (structure.enabled[i]) { + auto [first, count] = tilings[i]; + commands.push_back({(unsigned int) count, 1, (unsigned int) first, i}); + } + } + + vbos.commands.put(commands.begin(), commands.end(), GL_STREAM_DRAW); } } @@ -95,25 +123,29 @@ namespace vis { pipe.stage(solid); vao.iformat(0, 4, GL_UNSIGNED_INT); + vao.format(1, 3, GL_FLOAT); + + glVertexArrayBindingDivisor(vao, 1, 1); } void operator()(entt::registry ®) { - auto view = reg.view(); + auto view = reg.view(); - for (auto [entity, group, vbos]: view.each()) { + for (auto [entity, vbos]: view.each()) { const size_t N = 4; glBindProgramPipeline(pipe); - glProgramUniform3fv(solid, 2, 1, group.color.data()); - glBindBufferBase(GL_UNIFORM_BUFFER, 2, vbos.ubo); + glBindBufferBase(GL_UNIFORM_BUFFER, 2, vbos.uniform); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, vbos.vertices); - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, vbos.verts); + vao.vertexBuffer(0, vbos.indices); + vao.vertexBuffer(1, vbos.colors); - vao.vertexBuffer(0, vbos.ibo); + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, vbos.commands); glBindVertexArray(vao); - glDrawArrays(GL_POINTS, 0, vbos.ibo.count()); + glMultiDrawArraysIndirect(GL_POINTS, nullptr, vbos.commands.count(), 0); glBindVertexArray(0); glBindProgramPipeline(0); diff --git a/vis/src/main.cpp b/vis/src/main.cpp index db05ef2..151d40a 100644 --- a/vis/src/main.cpp +++ b/vis/src/main.cpp @@ -15,11 +15,13 @@ #include "comps.hpp" #include "fmt/core.h" +#include "fmt/ranges.h" #include #ifndef NDEBUG #include +#include #endif #ifdef _WIN32 @@ -36,8 +38,8 @@ struct Matrices { Eigen::Matrix4f proj; Eigen::Matrix4f view; - Matrices(const Eigen::Matrix4f &proj, const Eigen::Matrix4f &view) - : proj(proj), view(view) { + Matrices(Eigen::Matrix4f proj, Eigen::Matrix4f view) + : proj(std::move(proj)), view(std::move(view)) { } }; @@ -106,6 +108,23 @@ void show_overlay(State &state) { ImGui::End(); } +void show_options(entt::registry ®istry) { + auto view = registry.view>(); + + for (auto [entity, structure]: view.each()) { + ImGui::Begin("Structure View Options"); + + for (int i = 0; i < structure.hull.tilings.size(); ++i) { + std::string label = fmt::format("{}", structure.hull.subgroups[i]); + + ImGui::Checkbox(label.c_str(), (bool*) (&(structure.enabled[i]))); + ImGui::ColorEdit3(label.c_str(), structure.colors[i].data(), ImGuiColorEditFlags_NoLabel); + } + + ImGui::End(); + } +} + void set_style() { ImGui::StyleColorsDark(); @@ -135,16 +154,21 @@ int run(GLFWwindow* window, ImGuiContext* ctx) { state.dimension = 4; auto entity = registry.create(); + { + // todo move symbol and root to structure + // cache and recompute cells/points on frame (only if changed) in a system. - registry.emplace( - entity, - tc::schlafli({5, 3, 3, 2}), - vec5{0.80, 0.09, 0.09, 0.09, 0.09}, - vec3{0.90, 0.90, 0.90} - ); - registry.emplace(entity); + tc::Group group = tc::schlafli({5, 3, 3, 2}); + Points points(group, vec5{0.80, 0.3, 0.15, 0.15, 0.03}); + Hull<4> hull(group); - vis::upload_groups(registry); + auto& structure = registry.emplace>(entity, std::move(points), std::move(hull)); + registry.emplace(entity); + + structure.enabled[0] = false; // disable {0,1,2} cells + } + + vis::upload_structure(registry); auto ubo = cgl::Buffer(); glBindBufferBase(GL_UNIFORM_BUFFER, 1, ubo); @@ -163,6 +187,7 @@ int run(GLFWwindow* window, ImGuiContext* ctx) { ImGui::NewFrame(); show_overlay(state); + show_options(registry); ImGui::Render(); int width, height; @@ -171,10 +196,10 @@ int run(GLFWwindow* window, ImGuiContext* ctx) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - ubo.put(build(window, state, ctx)); + ubo.put(build(window, state, ctx), GL_STREAM_DRAW); { - auto &tform = registry.get(entity).tform; + auto &tform = registry.get>(entity).transform; if (!io.KeysDown[GLFW_KEY_SPACE]) { float speed = 1.0 / 8.0; @@ -202,7 +227,8 @@ int run(GLFWwindow* window, ImGuiContext* ctx) { tform.translation().w() = std::sin(state.time * 1.4) * 1.0; } - vis::upload_ubo(registry); + vis::upload_commands(registry); + vis::upload_uniforms(registry); renderer(registry);