[Bf-blender-cvs] [956a61be719] quadriflow: Initial quadriflow border preservation

Sebastian Parborg noreply at git.blender.org
Tue Sep 10 18:36:05 CEST 2019


Commit: 956a61be719395656c84dcc42f281f72352d6748
Author: Sebastian Parborg
Date:   Fri Aug 30 14:57:01 2019 +0200
Branches: quadriflow
https://developer.blender.org/rB956a61be719395656c84dcc42f281f72352d6748

Initial quadriflow border preservation

===================================================================

M	extern/quadriflow/blender_config.cmake
M	extern/quadriflow/src/hierarchy.cpp
M	extern/quadriflow/src/hierarchy.hpp
M	extern/quadriflow/src/main.cpp
M	extern/quadriflow/src/optimizer.cpp
M	extern/quadriflow/src/parametrizer-mesh.cpp
M	extern/quadriflow/src/parametrizer.hpp
M	intern/quadriflow/quadriflow_capi.cpp
M	intern/quadriflow/quadriflow_capi.hpp
M	source/blender/blenkernel/BKE_mesh_remesh_voxel.h
M	source/blender/blenkernel/intern/mesh_remesh_voxel.c
M	source/blender/editors/object/object_remesh.c

===================================================================

diff --git a/extern/quadriflow/blender_config.cmake b/extern/quadriflow/blender_config.cmake
index b0e4c947952..19500d67774 100644
--- a/extern/quadriflow/blender_config.cmake
+++ b/extern/quadriflow/blender_config.cmake
@@ -3,7 +3,7 @@
 
 set(QUADRIFLOW_STANDALONE FALSE)
 set(BUILD_PERFORMANCE_TEST FALSE)
-set(BUILD_LOG FALSE)
+set(BUILD_LOG TRUE)
 set(BUILD_GUROBI FALSE)
 set(BUILD_OPENMP ${WITH_OPENMP})
 set(BUILD_TBB FALSE)
diff --git a/extern/quadriflow/src/hierarchy.cpp b/extern/quadriflow/src/hierarchy.cpp
index 3806089a4d8..c333256a139 100644
--- a/extern/quadriflow/src/hierarchy.cpp
+++ b/extern/quadriflow/src/hierarchy.cpp
@@ -23,6 +23,11 @@ Hierarchy::Hierarchy() {
     mToLower.resize(MAX_DEPTH);
     mToUpper.resize(MAX_DEPTH);
     rng_seed = 0;
+
+    mCQ.reserve(MAX_DEPTH + 1);
+    mCQw.reserve(MAX_DEPTH + 1);
+    mCO.reserve(MAX_DEPTH + 1);
+    mCOw.reserve(MAX_DEPTH + 1);
 }
 
 #undef max
@@ -30,6 +35,7 @@ Hierarchy::Hierarchy() {
 void Hierarchy::Initialize(double scale, int with_scale) {
     this->with_scale = with_scale;
     generate_graph_coloring_deterministic(mAdj[0], mV[0].cols(), mPhases[0]);
+
     for (int i = 0; i < MAX_DEPTH; ++i) {
         DownsampleGraph(mAdj[i], mV[i], mN[i], mA[i], mV[i + 1], mN[i + 1], mA[i + 1], mToUpper[i],
                         mToLower[i], mAdj[i + 1]);
@@ -49,6 +55,11 @@ void Hierarchy::Initialize(double scale, int with_scale) {
     mS.resize(mV.size());
     mK.resize(mV.size());
 
+    mCO.resize(mV.size());
+    mCOw.resize(mV.size());
+    mCQ.resize(mV.size());
+    mCQw.resize(mV.size());
+
     //Set random seed
     srand(rng_seed);
 
@@ -1090,6 +1101,124 @@ void Hierarchy::PropagateEdge() {
     }
 }
 
+void Hierarchy::clearConstraints() {
+    int levels = mV.size();
+    if (levels == 0) return;
+    for (int i = 0; i < levels; ++i) {
+        int size = mV[i].cols();
+        mCQ[i].resize(3, size);
+        mCO[i].resize(3, size);
+        mCQw[i].resize(size);
+        mCOw[i].resize(size);
+        mCQw[i].setZero();
+        mCOw[i].setZero();
+    }
+}
+
+void Hierarchy::propagateConstraints() {
+    int levels = mV.size();
+    if (levels == 0) return;
+
+    for (int l = 0; l < levels - 1; ++l) {
+        auto& N = mN[l];
+        auto& N_next = mN[l + 1];
+        auto& V = mV[l];
+        auto& V_next = mV[l + 1];
+        auto& CQ = mCQ[l];
+        auto& CQ_next = mCQ[l + 1];
+        auto& CQw = mCQw[l];
+        auto& CQw_next = mCQw[l + 1];
+        auto& CO = mCO[l];
+        auto& CO_next = mCO[l + 1];
+        auto& COw = mCOw[l];
+        auto& COw_next = mCOw[l + 1];
+        auto& toUpper = mToUpper[l];
+        MatrixXd& S = mS[l];
+
+        for (uint32_t i = 0; i != mV[l + 1].cols(); ++i) {
+            Vector2i upper = toUpper.col(i);
+            Vector3d cq = Vector3d::Zero(), co = Vector3d::Zero();
+            float cqw = 0.0f, cow = 0.0f;
+
+            bool has_cq0 = CQw[upper[0]] != 0;
+            bool has_cq1 = upper[1] != -1 && CQw[upper[1]] != 0;
+            bool has_co0 = COw[upper[0]] != 0;
+            bool has_co1 = upper[1] != -1 && COw[upper[1]] != 0;
+
+            if (has_cq0 && !has_cq1) {
+                cq = CQ.col(upper[0]);
+                cqw = CQw[upper[0]];
+            } else if (has_cq1 && !has_cq0) {
+                cq = CQ.col(upper[1]);
+                cqw = CQw[upper[1]];
+            } else if (has_cq1 && has_cq0) {
+                Vector3d q_i = CQ.col(upper[0]);
+                Vector3d n_i = CQ.col(upper[0]);
+                Vector3d q_j = CQ.col(upper[1]);
+                Vector3d n_j = CQ.col(upper[1]);
+                auto result = compat_orientation_extrinsic_4(q_i, n_i, q_j, n_j);
+                cq = result.first * CQw[upper[0]] + result.second * CQw[upper[1]];
+                cqw = (CQw[upper[0]] + CQw[upper[1]]);
+            }
+            if (cq != Vector3d::Zero()) {
+                Vector3d n = N_next.col(i);
+                cq -= n.dot(cq) * n;
+                if (cq.squaredNorm() > RCPOVERFLOW) cq.normalize();
+            }
+
+            if (has_co0 && !has_co1) {
+                co = CO.col(upper[0]);
+                cow = COw[upper[0]];
+            } else if (has_co1 && !has_co0) {
+                co = CO.col(upper[1]);
+                cow = COw[upper[1]];
+            } else if (has_co1 && has_co0) {
+                double scale_x = mScale;
+                double scale_y = mScale;
+                if (with_scale) {
+                  // FIXME
+                    // scale_x *= S(0, i);
+                    // scale_y *= S(1, i);
+                }
+                double inv_scale_x = 1.0f / scale_x;
+                double inv_scale_y = 1.0f / scale_y;
+
+                double scale_x_1 = mScale;
+                double scale_y_1 = mScale;
+                if (with_scale) {
+                  // FIXME
+                    // scale_x_1 *= S(0, j);
+                    // scale_y_1 *= S(1, j);
+                }
+                double inv_scale_x_1 = 1.0f / scale_x_1;
+                double inv_scale_y_1 = 1.0f / scale_y_1;
+                auto result = compat_position_extrinsic_4(
+                    V.col(upper[0]), N.col(upper[0]), CQ.col(upper[0]), CO.col(upper[0]),
+                    V.col(upper[1]), N.col(upper[1]), CQ.col(upper[1]), CO.col(upper[1]), scale_x,
+                    scale_y, inv_scale_x, inv_scale_y, scale_x_1, scale_y_1, inv_scale_x_1,
+                    inv_scale_y_1);
+                cow = COw[upper[0]] + COw[upper[1]];
+                co = (result.first * COw[upper[0]] + result.second * COw[upper[1]]) / cow;
+            }
+            if (co != Vector3d::Zero()) {
+                Vector3d n = N_next.col(i), v = V_next.col(i);
+                co -= n.dot(cq - v) * n;
+            }
+#if 0
+                        cqw *= 0.5f;
+                        cow *= 0.5f;
+#else
+            if (cqw > 0) cqw = 1;
+            if (cow > 0) cow = 1;
+#endif
+
+            CQw_next[i] = cqw;
+            COw_next[i] = cow;
+            CQ_next.col(i) = cq;
+            CO_next.col(i) = co;
+        }
+    }
+}
 #ifdef WITH_CUDA
 #include <cuda_runtime.h>
 
diff --git a/extern/quadriflow/src/hierarchy.hpp b/extern/quadriflow/src/hierarchy.hpp
index 58132f6d7cb..8403038de4f 100644
--- a/extern/quadriflow/src/hierarchy.hpp
+++ b/extern/quadriflow/src/hierarchy.hpp
@@ -40,6 +40,9 @@ class Hierarchy {
     void SaveToFile(FILE* fp);
     void LoadFromFile(FILE* fp);
 
+    void clearConstraints();
+    void propagateConstraints();
+
     double mScale;
     int rng_seed;
 
@@ -58,6 +61,12 @@ class Hierarchy {
     std::vector<MatrixXd> mS;
     std::vector<MatrixXd> mK;
 
+    // constraints
+    std::vector<MatrixXd> mCQ;
+    std::vector<MatrixXd> mCO;
+    std::vector<VectorXd> mCQw;
+    std::vector<VectorXd> mCOw;
+
     int with_scale;
 
     // upper: fine to coarse
diff --git a/extern/quadriflow/src/main.cpp b/extern/quadriflow/src/main.cpp
index e4a6ec6ccb6..41ba1ab82d0 100644
--- a/extern/quadriflow/src/main.cpp
+++ b/extern/quadriflow/src/main.cpp
@@ -30,6 +30,8 @@ int main(int argc, char** argv) {
             output_obj = argv[i + 1];
         } else if (strcmp(argv[i], "-sharp") == 0) {
             field.flag_preserve_sharp = 1;
+        } else if (strcmp(argv[i], "-border") == 0) {
+            field.flag_preserve_border = 1;
         } else if (strcmp(argv[i], "-adaptive") == 0) {
             field.flag_adaptive_scale = 1;
         } else if (strcmp(argv[i], "-mcf") == 0) {
@@ -54,6 +56,29 @@ int main(int argc, char** argv) {
     t2 = GetCurrentTime64();
     printf("Use %lf seconds\n", (t2 - t1) * 1e-3);
 
+    if (field.flag_preserve_border) {
+        printf("Add border constrains...\n");
+        Hierarchy& mRes = field.hierarchy;
+        mRes.clearConstraints();
+        for (uint32_t i = 0; i < 3 * mRes.mF.cols(); ++i) {
+            if (mRes.mE2E[i] == -1) {
+                uint32_t i0 = mRes.mF(i % 3, i / 3);
+                uint32_t i1 = mRes.mF((i + 1) % 3, i / 3);
+                Vector3d p0 = mRes.mV[0].col(i0), p1 = mRes.mV[0].col(i1);
+                Vector3d edge = p1 - p0;
+                if (edge.squaredNorm() > 0) {
+                    edge.normalize();
+                    mRes.mCO[0].col(i0) = p0;
+                    mRes.mCO[0].col(i1) = p1;
+                    mRes.mCQ[0].col(i0) = mRes.mCQ[0].col(i1) = edge;
+                    mRes.mCQw[0][i0] = mRes.mCQw[0][i1] = mRes.mCOw[0][i0] = mRes.mCOw[0][i1] =
+                        1.0;
+                }
+            }
+        }
+        mRes.propagateConstraints();
+    }
+
     printf("Solve Orientation Field...\n");
     t1 = GetCurrentTime64();
 
diff --git a/extern/quadriflow/src/optimizer.cpp b/extern/quadriflow/src/optimizer.cpp
index 24d6f7f9b73..47004f01126 100644
--- a/extern/quadriflow/src/optimizer.cpp
+++ b/extern/quadriflow/src/optimizer.cpp
@@ -42,6 +42,8 @@ void Optimizer::optimize_orientations(Hierarchy& mRes) {
     for (int level = mRes.mN.size() - 1; level >= 0; --level) {
         AdjacentMatrix& adj = mRes.mAdj[level];
         const MatrixXd& N = mRes.mN[level];
+        const MatrixXd& CQ = mRes.mCQ[level];
+        const VectorXd& CQw = mRes.mCQw[level];
         MatrixXd& Q = mRes.mQ[level];
         auto& phases = mRes.mPhases[level];
         for (int iter = 0; iter < levelIterations; ++iter) {
@@ -69,6 +71,20 @@ void Optimizer::optimize_orientations(Hierarchy& mRes) {
                         double norm = sum.norm();
                         if (norm > RCPOVERFLOW) sum /= norm;
                     }
+
+                    if (CQw.size() > 0) {
+                        float cw = CQw[i];
+                        if (cw != 0) {
+                            std::pair<Vector3d, Vector3d> value =
+                                compat_orientation_extrinsic_4(sum, n_i, CQ.col(i), n_i);
+                            sum = value.first * (1 - cw) + value.second * cw;
+                            sum -= n_i * n_i.dot(sum);
+
+                            float norm = sum.norm();
+                            if (norm > RCPOVERFLOW) sum /= norm;
+                        }
+                    }
+
                     if (weight_sum

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list