diff --git a/.gitignore b/.gitignore index e15dd28..5d13a47 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ build compile_commands.json .clangd CMakeSettings.json -.vs \ No newline at end of file +.vs +snapshots diff --git a/CMakeLists.txt b/CMakeLists.txt index b698165..94cee32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,7 @@ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/pd/positional_constraint.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pd/solver.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pd/strain_constraint.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/pd/utils.h # ui ${CMAKE_CURRENT_SOURCE_DIR}/include/ui/mouse_down_handler.h diff --git a/include/pd/solver.h b/include/pd/solver.h index e8f96d9..4eadcac 100644 --- a/include/pd/solver.h +++ b/include/pd/solver.h @@ -10,6 +10,12 @@ #include #include +// libigl +#include + +// storing data +#include + namespace pd { namespace detail { @@ -51,6 +57,13 @@ class solver_t void set_dirty() { dirty_ = true; } void set_clean() { dirty_ = false; } bool ready() const { return !dirty_; } + + bool is_experinent_set() const { return exp_set_; } + + bool record_ = true; + bool collect_snapshots() { return record_; }; + std::string snapshots_directory = "../../../snapshots"; + void prepare(scalar_type dt) { dt_ = dt; @@ -87,7 +100,7 @@ class solver_t set_clean(); } - void step(Eigen::MatrixXd const& fext, int num_iterations = 10) + void step(Eigen::MatrixXd const& fext, int num_iterations = 10, int frame = 0) { auto const& constraints = model_->constraints(); auto& positions = model_->positions(); @@ -145,6 +158,16 @@ class solver_t Eigen::MatrixXd const qn_plus_1 = detail::unflatten(q); velocities = (qn_plus_1 - positions) * dt_inv; positions = qn_plus_1; + + if (this->collect_snapshots()) + { + //std::cout << experiment; + std::filesystem::create_directory(snapshots_directory); // create directory if doesnt exist + igl::writePLY( + snapshots_directory + "/somemesh" + std::to_string(frame) + ".ply", + positions, + model_->faces()); + } } private: @@ -153,6 +176,8 @@ class solver_t Eigen::SimplicialCholesky> cholesky_decomposition_; Eigen::MatrixXd A_; scalar_type dt_; + + bool exp_set_; }; } // namespace pd diff --git a/include/pd/utils.h b/include/pd/utils.h new file mode 100644 index 0000000..72dd95d --- /dev/null +++ b/include/pd/utils.h @@ -0,0 +1,12 @@ + +#include +#include +#include + +inline std::string float_to_str(float value) +{ + std::stringstream stream; + stream << std::setprecision(std::numeric_limits::digits10 + 1); + stream << value; + return stream.str(); +} \ No newline at end of file diff --git a/include/ui/pre_draw_handler.h b/include/ui/pre_draw_handler.h index b206d62..65f7f30 100644 --- a/include/ui/pre_draw_handler.h +++ b/include/ui/pre_draw_handler.h @@ -14,13 +14,17 @@ struct pre_draw_handler_t physics_params_t* physics_params; pd::solver_t* solver; Eigen::MatrixX3d* fext; + pre_draw_handler_t( std::function is_model_ready, physics_params_t* physics_params, pd::solver_t* solver, Eigen::MatrixX3d* fext) - : is_model_ready(is_model_ready), physics_params(physics_params), solver(solver), fext(fext) + : is_model_ready(is_model_ready), + physics_params(physics_params), + solver(solver), + fext(fext) { } diff --git a/src/main.cpp b/src/main.cpp index 7e4fc7e..66c244c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,7 @@ #include "geometry/get_simple_cloth_model.h" #include "pd/deformable_mesh.h" #include "pd/solver.h" +#include "pd/utils.h" #include "ui/mouse_down_handler.h" #include "ui/mouse_move_handler.h" #include "ui/physics_params.h" @@ -21,6 +22,8 @@ #include #include +#include + int main(int argc, char** argv) { pd::deformable_mesh_t model{}; @@ -28,6 +31,7 @@ int main(int argc, char** argv) ui::picking_state_t picking_state{}; ui::physics_params_t physics_params{}; pd::solver_t solver; + //std::string experiment_name = ""; auto const is_model_ready = [&]() { return model.positions().rows() > 0; @@ -91,7 +95,11 @@ int main(int argc, char** argv) if (ImGui::Button("Load triangle mesh", ImVec2((w - p) / 2.f, 0))) { std::string const filename = igl::file_dialog_open(); + std::filesystem::path const mesh{filename}; + + //experiment_name = experiment_name + mesh.stem().u8string() + "_ tri_"; + if (std::filesystem::exists(mesh) && std::filesystem::is_regular_file(mesh)) { Eigen::MatrixXd V; @@ -113,6 +121,9 @@ int main(int argc, char** argv) { std::string const filename = igl::file_dialog_open(); std::filesystem::path const mesh{filename}; + + //experiment_name = experiment_name + mesh.stem().u8string() + "_tet_"; + if (std::filesystem::exists(mesh) && std::filesystem::is_regular_file(mesh)) { Eigen::MatrixXd V; @@ -147,6 +158,8 @@ int main(int argc, char** argv) F.resize(1, 3); F.row(0) = Eigen::RowVector3i{0, 1, 2}; + //experiment_name = experiment_name + "to2D_"; + reset_simulation_model(V, F, F, false); } ImGui::TreePop(); @@ -168,6 +181,7 @@ int main(int argc, char** argv) static_cast(bar_height), static_cast(bar_depth)); + //experiment_name = experiment_name + "Bar_tet_"; reset_simulation_model(V, F, T, true); } @@ -185,6 +199,7 @@ int main(int argc, char** argv) { auto [V, F] = geometry::get_simple_cloth_model(cloth_width, cloth_height); + //experiment_name = experiment_name + "Cloth_tri_"; reset_simulation_model(V, F, F, true); } @@ -200,6 +215,7 @@ int main(int argc, char** argv) Eigen::MatrixXi F; Eigen::VectorXi J; igl::decimate(model.positions(), model.faces(), max_facet_count, V, F, J); + reset_simulation_model(V, F, F); } ImGui::TreePop(); @@ -214,6 +230,7 @@ int main(int argc, char** argv) viewer.core().align_camera_center(model.positions()); } ImGui::TreePop(); + //experiment_name = experiment_name + "_to3D_"; } std::string const vertex_count = std::to_string(model.positions().rows()); std::string const element_count = std::to_string(model.elements().rows()); @@ -294,11 +311,16 @@ int main(int argc, char** argv) if (is_constraint_type_active[0]) { model.constrain_edge_lengths(physics_params.edge_constraint_wi); + /*experiment_name = experiment_name + "constrain_edge_lengths_wi" + + float_to_str(physics_params.edge_constraint_wi);*/ } if (is_constraint_type_active[1]) { model.constrain_deformation_gradient( physics_params.deformation_gradient_constraint_wi); + /*experiment_name = experiment_name + + "constrain_deformation_gradient_wi" + + float_to_str(physics_params.deformation_gradient_constraint_wi);*/ } if (is_constraint_type_active[2]) { @@ -306,11 +328,19 @@ int main(int argc, char** argv) sigma_min, sigma_max, physics_params.strain_limit_constraint_wi); + + /* experiment_name = experiment_name + + "constrain_strain_wi" + + float_to_str(physics_params.strain_limit_constraint_wi) + + "_min_" + float_to_str(sigma_min) + + "_max_" + float_to_str(sigma_max);*/ } } std::string const constraint_count = std::to_string(model.constraints().size()); ImGui::BulletText(std::string("Constraints: " + constraint_count).c_str()); ImGui::TreePop(); + + //experiment_name = experiment_name + "Constraints: " + constraint_count; } ImGui::InputFloat("Timestep", &physics_params.dt, 0.01f, 0.1f, "%.4f"); ImGui::InputInt("Solver iterations", &physics_params.solver_iterations); diff --git a/src/ui/pre_draw_handler.cpp b/src/ui/pre_draw_handler.cpp index ac31df4..ed360c9 100644 --- a/src/ui/pre_draw_handler.cpp +++ b/src/ui/pre_draw_handler.cpp @@ -2,9 +2,11 @@ namespace ui { +unsigned int frame_count = 1; bool pre_draw_handler_t::operator()(igl::opengl::glfw::Viewer& viewer) { pd::deformable_mesh_t* model = solver->model(); + if (!is_model_ready()) return false; @@ -36,7 +38,9 @@ bool pre_draw_handler_t::operator()(igl::opengl::glfw::Viewer& viewer) solver->prepare(physics_params->dt); } - solver->step(*fext, physics_params->solver_iterations); + solver->step(*fext, physics_params->solver_iterations, frame_count); + + frame_count++; fext->setZero(); viewer.data().clear();