Blender V4.3
geometry_data_retrieval.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include "slim.h"
13#include <Eigen/Dense>
14
15#include "BLI_assert.h"
16#include "area_compensation.h"
19
20#include "BLI_assert.h"
21
22using namespace Eigen;
23
24namespace slim {
25
27 : number_of_vertices(chart.verts_num),
28 number_of_faces(chart.faces_num),
29 /* `n_edges` in transferred_data accounts for boundary edges only once. */
30 number_of_edges_twice(chart.edges_num + chart.boundary_vertices_num),
31 number_of_boundary_vertices(chart.boundary_vertices_num),
32 number_of_pinned_vertices(chart.pinned_vertices_num),
33 use_weights(mt.use_weights),
34 weight_influence(mt.weight_influence),
35 vertex_positions3d(chart.v_matrices.data(), number_of_vertices, columns_3),
36 uv_positions2d(chart.uv_matrices.data(), number_of_vertices, columns_2),
37 positions_of_pinned_vertices2d(),
38 positions_of_explicitly_pinned_vertices2d(
39 number_of_pinned_vertices != 0 ? chart.pp_matrices.data() : nullptr,
40 number_of_pinned_vertices,
41 columns_2),
42 faces_by_vertexindices(chart.f_matrices.data(), number_of_faces, columns_3),
43 edges_by_vertexindices(chart.e_matrices.data(), number_of_edges_twice, columns_2),
44 pinned_vertex_indices(),
45 explicitly_pinned_vertex_indices(number_of_pinned_vertices != 0 ? chart.p_matrices.data() :
46 nullptr,
47 number_of_pinned_vertices),
48 edge_lengths(chart.el_vectors.data(), number_of_edges_twice),
49 boundary_vertex_indices(chart.b_vectors.data(), number_of_boundary_vertices),
50 weights_per_vertex(chart.w_vectors.data(), number_of_vertices)
51{
53}
54
55static void create_weights_per_face(SLIMData &slim_data)
56{
57 if (!slim_data.valid) {
58 return;
59 }
60
61 if (!slim_data.withWeightedParameterization) {
62 slim_data.weightPerFaceMap = Eigen::VectorXf::Ones(slim_data.F.rows());
63 return;
64 }
65
66 slim_data.weightPerFaceMap = Eigen::VectorXf(slim_data.F.rows());
67
68 /* The actual weight is `max_factor ^ (2 * (mean - 0.5))` */
69 int weight_influence_sign = (slim_data.weightInfluence >= 0) ? 1 : -1;
70 double max_factor = std::abs(slim_data.weightInfluence) + 1;
71
72 for (int fid = 0; fid < slim_data.F.rows(); fid++) {
73 Eigen::RowVector3i row = slim_data.F.row(fid);
74 float w1, w2, w3, mean, weight_factor, flipped_mean;
75 w1 = slim_data.weightmap(row(0));
76 w2 = slim_data.weightmap(row(1));
77 w3 = slim_data.weightmap(row(2));
78 mean = (w1 + w2 + w3) / 3;
79 flipped_mean = 1 - mean;
80
81 weight_factor = std::pow(max_factor, weight_influence_sign * 2 * (flipped_mean - 0.5));
82 slim_data.weightPerFaceMap(fid) = weight_factor;
83 }
84}
85
86void GeometryData::set_geometry_data_matrices(SLIMData &slim_data) const
87{
88 if (!slim_data.valid) {
89 return;
90 }
91
92 slim_data.V = vertex_positions3d;
93 slim_data.F = faces_by_vertexindices;
94 slim_data.b = pinned_vertex_indices;
95 slim_data.bc = positions_of_pinned_vertices2d;
96 slim_data.V_o = uv_positions2d;
97 slim_data.oldUVs = uv_positions2d;
98 slim_data.weightmap = weights_per_vertex;
99 create_weights_per_face(slim_data);
100}
101
102bool GeometryData::has_valid_preinitialized_map() const
103{
104 if (uv_positions2d.rows() == vertex_positions3d.rows() && uv_positions2d.cols() == columns_2) {
105
106 int number_of_flips = count_flips(faces_by_vertexindices, uv_positions2d);
107 bool no_flips_present = (number_of_flips == 0);
108 return (no_flips_present);
109 }
110 return false;
111}
112
113/* If we use interactive parametrisation, we usually start form an existing, flip-free unwrapping.
114 * Also, pinning of vertices has some issues with initialisation with convex border.
115 * We therefore may want to skip initialization. however, to skip initialization we need a
116 * preexisting valid starting map. */
117bool GeometryData::can_initialization_be_skipped(bool skip_initialization) const
118{
119 return (skip_initialization && has_valid_preinitialized_map());
120}
121
123 bool skip_initialization,
124 int reflection_mode) const
125{
126 BLI_assert(slim_data.valid);
127
128 slim_data.skipInitialization = can_initialization_be_skipped(skip_initialization);
130 slim_data.reflection_mode = reflection_mode;
132 set_geometry_data_matrices(slim_data);
133
134 double penalty_for_violating_pinned_positions = 10.0e100;
135 slim_data.soft_const_p = penalty_for_violating_pinned_positions;
137
138 initialize_if_needed(slim_data);
139
142
143 slim_precompute(slim_data.V,
144 slim_data.F,
145 slim_data.V_o,
146 slim_data,
147 slim_data.slim_energy,
148 slim_data.b,
149 slim_data.bc,
150 slim_data.soft_const_p);
151}
152
153void GeometryData::combine_matrices_of_pinned_and_boundary_vertices()
154{
155 /* Over - allocate pessimistically to avoid multiple reallocation. */
156 int upper_bound_on_number_of_pinned_vertices = number_of_boundary_vertices +
158 pinned_vertex_indices = VectorXi(upper_bound_on_number_of_pinned_vertices);
159 positions_of_pinned_vertices2d = MatrixXd(upper_bound_on_number_of_pinned_vertices, columns_2);
160
161 /* Since border vertices use vertex indices 0 ... #bordervertices we can do: */
165
166 int index = number_of_boundary_vertices;
167 int highest_vertex_index = (boundary_vertex_indices)(index - 1);
168
169 for (Map<VectorXi>::InnerIterator it(explicitly_pinned_vertex_indices, 0); it; ++it) {
170 int vertex_index = it.value();
171 if (vertex_index > highest_vertex_index) {
172 pinned_vertex_indices(index) = vertex_index;
173 positions_of_pinned_vertices2d.row(index) = uv_positions2d.row(vertex_index);
174 index++;
175 }
176 }
177
178 int actual_number_of_pinned_vertices = index;
179 pinned_vertex_indices.conservativeResize(actual_number_of_pinned_vertices);
180 positions_of_pinned_vertices2d.conservativeResize(actual_number_of_pinned_vertices, columns_2);
181
182 number_of_pinned_vertices = actual_number_of_pinned_vertices;
183}
184
185/* If the border is fixed, we simply pin the border vertices additionally to other pinned vertices.
186 */
187void GeometryData::retrieve_pinned_vertices(bool border_vertices_are_pinned)
188{
189 if (border_vertices_are_pinned) {
190 combine_matrices_of_pinned_and_boundary_vertices();
191 }
192 else {
195 }
196}
197
198void GeometryData::initialize_if_needed(SLIMData &slim_data) const
199{
200 BLI_assert(slim_data.valid);
201
202 if (!slim_data.skipInitialization) {
203 initialize_uvs(slim_data);
204 }
205}
206
207void GeometryData::initialize_uvs(SLIMData &slim_data) const
208{
209 Eigen::MatrixXd uv_positions_of_boundary(boundary_vertex_indices.rows(), 2);
210 map_vertices_to_convex_border(uv_positions_of_boundary);
211
212 bool all_vertices_on_boundary = (slim_data.V_o.rows() == uv_positions_of_boundary.rows());
213 if (all_vertices_on_boundary) {
214 slim_data.V_o = uv_positions_of_boundary;
215 return;
216 }
217
223 uv_positions_of_boundary,
224 slim_data.V_o);
225}
226
227} // namespace slim
#define BLI_assert(a)
Definition BLI_assert.h:50
void edge_lengths(const Eigen::PlainObjectBase< DerivedV > &V, const Eigen::PlainObjectBase< DerivedF > &F, Eigen::PlainObjectBase< DerivedL > &L)
void map_vertices_to_convex_border(Eigen::MatrixXd &vertex_positions)
void slim_precompute(Eigen::MatrixXd &V, Eigen::MatrixXi &F, Eigen::MatrixXd &V_init, SLIMData &data, SLIMData::SLIM_ENERGY slim_energy, Eigen::VectorXi &b, Eigen::MatrixXd &bc, double soft_p)
Definition slim.cpp:649
int count_flips(const Eigen::MatrixXi &f, const Eigen::MatrixXd &uv)
void transform_initialization_if_necessary(SLIMData &slim_data)
void mvc(const Eigen::MatrixXi &f, const Eigen::MatrixXd &v, const Eigen::MatrixXi &e, const Eigen::VectorXd &el, const Eigen::VectorXi &bnd, const Eigen::MatrixXd &bnd_uv, Eigen::MatrixXd &uv)
static void create_weights_per_face(SLIMData &slim_data)
void correct_mesh_surface_area_if_necessary(SLIMData &slim_data)
void construct_slim_data(SLIMData &slim_data, bool skip_initialization, int reflection_mode) const
Map< VectorXi > explicitly_pinned_vertex_indices
Map< MatrixXi > edges_by_vertexindices
Map< VectorXi > boundary_vertex_indices
Map< MatrixXd > vertex_positions3d
void retrieve_pinned_vertices(bool border_vertices_are_pinned)
GeometryData(const MatrixTransfer &mt, MatrixTransferChart &chart)
Map< MatrixXi > faces_by_vertexindices
Map< VectorXf > weights_per_vertex
Map< Matrix< double, Dynamic, Dynamic, RowMajor > > positions_of_explicitly_pinned_vertices2d
bool withWeightedParameterization
Definition slim.h:63
Eigen::MatrixXi F
Definition slim.h:30
Eigen::MatrixXd bc
Definition slim.h:44
Eigen::VectorXf weightPerFaceMap
Definition slim.h:65
bool skipInitialization
Definition slim.h:51
Eigen::VectorXi b
Definition slim.h:43
SLIM_ENERGY slim_energy
Definition slim.h:39
Eigen::VectorXf weightmap
Definition slim.h:64
Eigen::MatrixXd V
Definition slim.h:29
@ SYMMETRIC_DIRICHLET
Definition slim.h:34
bool valid
Definition slim.h:26
double weightInfluence
Definition slim.h:66
int reflection_mode
Definition slim.h:50
Eigen::MatrixXd V_o
Definition slim.h:56
double soft_const_p
Definition slim.h:45