Blender V4.5
subdiv_converter_mesh.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2018 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "subdiv_converter.hh"
10
11#include <cstring>
12
13#include "BKE_attribute.hh"
14#include "BKE_customdata.hh"
15#include "BKE_mesh.hh"
16#include "BKE_mesh_mapping.hh"
17#include "BKE_subdiv.hh"
18
19#include "MEM_guardedalloc.h"
20
22
23namespace blender::bke::subdiv {
24
25/* Enable work-around for non-working CPU evaluator when using bilinear scheme.
26 * This forces Catmark scheme with all edges marked as infinitely sharp. */
27#define BUGGY_SIMPLE_SCHEME_WORKAROUND 1
28
31 const Mesh *mesh;
37
38 /* CustomData layer for vertex sharpnesses. */
40 /* CustomData layer for edge sharpness. */
42 /* Indexed by loop index, value denotes index of face-varying vertex
43 * which corresponds to the UV coordinate.
44 */
47 /* Indexed by coarse mesh elements, gives index of corresponding element
48 * with ignoring all non-manifold entities.
49 *
50 * NOTE: This isn't strictly speaking manifold, this is more like non-loose
51 * geometry index. As in, index of element as if there were no loose edges
52 * or vertices in the mesh.
53 */
55 /* Indexed by vertex index from mesh, corresponds to whether this vertex has
56 * infinite sharpness due to non-manifold topology.
57 */
59 /* Reverse mapping to above. */
62 /* Number of non-loose elements. */
65};
66
68{
69#if BUGGY_SIMPLE_SCHEME_WORKAROUND
70 (void)converter;
71 return OSD_SCHEME_CATMARK;
72#else
73 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
74 if (storage->settings.is_simple) {
76 }
77 else {
78 return OSD_SCHEME_CATMARK;
79 }
80#endif
81}
82
90
98
99static bool specifies_full_topology(const OpenSubdiv_Converter * /*converter*/)
100{
101 return false;
102}
103
104static int get_num_edges(const OpenSubdiv_Converter *converter)
105{
106 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
107 return storage->num_manifold_edges;
108}
109
110static int get_num_vertices(const OpenSubdiv_Converter *converter)
111{
112 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
113 return storage->num_manifold_vertices;
114}
115
116static void get_face_vertices(const OpenSubdiv_Converter *converter,
117 int manifold_face_index,
118 int *manifold_face_vertices)
119{
120 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
121 const IndexRange face = storage->faces[manifold_face_index];
122 for (int i = 0; i < face.size(); i++) {
123 const int vert = storage->corner_verts[face[i]];
124 manifold_face_vertices[i] = storage->manifold_vertex_index[vert];
125 }
126}
127
128static void get_edge_vertices(const OpenSubdiv_Converter *converter,
129 int manifold_edge_index,
130 int *manifold_edge_vertices)
131{
132 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
133 const int edge_index = storage->manifold_edge_index_reverse[manifold_edge_index];
134 const int2 &edge = storage->edges[edge_index];
135 manifold_edge_vertices[0] = storage->manifold_vertex_index[edge[0]];
136 manifold_edge_vertices[1] = storage->manifold_vertex_index[edge[1]];
137}
138
139static float get_edge_sharpness(const OpenSubdiv_Converter *converter, int manifold_edge_index)
140{
141 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
142#if BUGGY_SIMPLE_SCHEME_WORKAROUND
143 if (storage->settings.is_simple) {
144 return 10.0f;
145 }
146#endif
147 if (storage->cd_edge_crease.is_empty()) {
148 return 0.0f;
149 }
150 const int edge_index = storage->manifold_edge_index_reverse[manifold_edge_index];
151 return crease_to_sharpness(storage->cd_edge_crease[edge_index]);
152}
153
155 int manifold_vertex_index)
156{
157 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
158#if BUGGY_SIMPLE_SCHEME_WORKAROUND
159 if (storage->settings.is_simple) {
160 return true;
161 }
162#endif
163 if (storage->infinite_sharp_vertices_map.is_empty()) {
164 return false;
165 }
166 const int vertex_index = storage->manifold_vertex_index_reverse[manifold_vertex_index];
167 return storage->infinite_sharp_vertices_map[vertex_index];
168}
169
170static float get_vertex_sharpness(const OpenSubdiv_Converter *converter, int manifold_vertex_index)
171{
172 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
173 if (storage->cd_vertex_crease.is_empty()) {
174 return 0.0f;
175 }
176 const int vertex_index = storage->manifold_vertex_index_reverse[manifold_vertex_index];
177 return crease_to_sharpness(storage->cd_vertex_crease[vertex_index]);
178}
179
180static int get_num_uv_layers(const OpenSubdiv_Converter *converter)
181{
182 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
183 const Mesh *mesh = storage->mesh;
184 return CustomData_number_of_layers(&mesh->corner_data, CD_PROP_FLOAT2);
185}
186
187static void precalc_uv_layer(const OpenSubdiv_Converter *converter, const int layer_index)
188{
189 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
190 const Mesh *mesh = storage->mesh;
191 const float(*mloopuv)[2] = static_cast<const float(*)[2]>(
192 CustomData_get_layer_n(&mesh->corner_data, CD_PROP_FLOAT2, layer_index));
193 const int num_vert = mesh->verts_num;
194 const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
195 /* Initialize memory required for the operations. */
196 if (storage->loop_uv_indices == nullptr) {
197 storage->loop_uv_indices = MEM_malloc_arrayN<int>(size_t(mesh->corners_num),
198 "loop uv vertex index");
199 }
200 UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(storage->faces,
201 nullptr,
202 nullptr,
203 storage->corner_verts.data(),
204 mloopuv,
205 num_vert,
206 limit,
207 false,
208 true);
209 /* NOTE: First UV vertex is supposed to be always marked as separate. */
210 storage->num_uv_coordinates = -1;
211 for (int vertex_index = 0; vertex_index < num_vert; vertex_index++) {
212 const UvMapVert *uv_vert = BKE_mesh_uv_vert_map_get_vert(uv_vert_map, vertex_index);
213 while (uv_vert != nullptr) {
214 if (uv_vert->separate) {
215 storage->num_uv_coordinates++;
216 }
217 const IndexRange face = storage->faces[uv_vert->face_index];
218 const int global_loop_index = face.start() + uv_vert->loop_of_face_index;
219 storage->loop_uv_indices[global_loop_index] = storage->num_uv_coordinates;
220 uv_vert = uv_vert->next;
221 }
222 }
223 /* So far this value was used as a 0-based index, actual number of UV
224 * vertices is 1 more.
225 */
226 storage->num_uv_coordinates += 1;
227 BKE_mesh_uv_vert_map_free(uv_vert_map);
228}
229
230static void finish_uv_layer(const OpenSubdiv_Converter * /*converter*/) {}
231
232static int get_num_uvs(const OpenSubdiv_Converter *converter)
233{
234 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
235 return storage->num_uv_coordinates;
236}
237
239 const int face_index,
240 const int corner)
241{
242 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
243 const IndexRange face = storage->faces[face_index];
244 return storage->loop_uv_indices[face.start() + corner];
245}
246
247static void free_user_data(const OpenSubdiv_Converter *converter)
248{
249 ConverterStorage *user_data = static_cast<ConverterStorage *>(converter->user_data);
250 MEM_SAFE_FREE(user_data->loop_uv_indices);
254 MEM_delete(user_data);
255}
256
258{
259 converter->getSchemeType = get_scheme_type;
263
264 converter->getNumEdges = get_num_edges;
265 converter->getNumVertices = get_num_vertices;
266
268 converter->getFaceEdges = nullptr;
269
271 converter->getNumEdgeFaces = nullptr;
272 converter->getEdgeFaces = nullptr;
274
275 converter->getNumVertexEdges = nullptr;
276 converter->getVertexEdges = nullptr;
277 converter->getNumVertexFaces = nullptr;
278 converter->getVertexFaces = nullptr;
281
283 converter->precalcUVLayer = precalc_uv_layer;
284 converter->finishUVLayer = finish_uv_layer;
285 converter->getNumUVCoordinates = get_num_uvs;
287
288 converter->freeUserData = free_user_data;
289}
290
291static void initialize_manifold_index_array(const BitSpan not_used_map,
292 const int num_elements,
293 int **r_indices,
294 int **r_indices_reverse,
295 int *r_num_manifold_elements)
296{
297 int *indices = nullptr;
298 if (r_indices != nullptr) {
299 indices = MEM_malloc_arrayN<int>(size_t(num_elements), "manifold indices");
300 }
301 int *indices_reverse = nullptr;
302 if (r_indices_reverse != nullptr) {
303 indices_reverse = MEM_malloc_arrayN<int>(size_t(num_elements), "manifold indices reverse");
304 }
305 int offset = 0;
306 for (int i = 0; i < num_elements; i++) {
307 if (not_used_map.is_empty() || !not_used_map[i]) {
308 if (indices != nullptr) {
309 indices[i] = i - offset;
310 }
311 if (indices_reverse != nullptr) {
312 indices_reverse[i - offset] = i;
313 }
314 }
315 else {
316 if (indices != nullptr) {
317 indices[i] = -1;
318 }
319 offset++;
320 }
321 }
322 if (r_indices != nullptr) {
323 *r_indices = indices;
324 }
325 if (r_indices_reverse != nullptr) {
326 *r_indices_reverse = indices_reverse;
327 }
328 *r_num_manifold_elements = num_elements - offset;
329}
330
332{
333 const Mesh *mesh = storage->mesh;
334 const bke::LooseVertCache &loose_verts = mesh->verts_no_face();
335 const bke::LooseEdgeCache &loose_edges = mesh->loose_edges();
337 mesh->verts_num,
338 &storage->manifold_vertex_index,
340 &storage->num_manifold_vertices);
342 mesh->edges_num,
343 nullptr,
345 &storage->num_manifold_edges);
346 /* Initialize infinite sharp mapping. */
347 if (loose_edges.count > 0) {
348 const Span<int2> edges = storage->edges;
349 storage->infinite_sharp_vertices_map.resize(mesh->verts_num, false);
350 for (int edge_index = 0; edge_index < mesh->edges_num; edge_index++) {
351 if (loose_edges.is_loose_bits[edge_index]) {
352 const int2 edge = edges[edge_index];
353 storage->infinite_sharp_vertices_map[edge[0]].set();
354 storage->infinite_sharp_vertices_map[edge[1]].set();
355 }
356 }
357 }
358}
359
361 const Settings *settings,
362 const Mesh *mesh)
363{
364 ConverterStorage *user_data = MEM_new<ConverterStorage>(__func__);
365 user_data->settings = *settings;
366 user_data->mesh = mesh;
367 user_data->vert_positions = mesh->vert_positions();
368 user_data->edges = mesh->edges();
369 user_data->faces = mesh->faces();
370 user_data->corner_verts = mesh->corner_verts();
371 user_data->corner_edges = mesh->corner_edges();
372 if (settings->use_creases) {
373 const AttributeAccessor attributes = mesh->attributes();
374 user_data->cd_vertex_crease = *attributes.lookup<float>("crease_vert", AttrDomain::Point);
375 user_data->cd_edge_crease = *attributes.lookup<float>("crease_edge", AttrDomain::Edge);
376 }
377 user_data->loop_uv_indices = nullptr;
379 converter->user_data = user_data;
380}
381
383 const Settings *settings,
384 const Mesh *mesh)
385{
386 converter->faces = mesh->faces();
387 init_functions(converter);
388 init_user_data(converter, settings, mesh);
389}
390
391} // namespace blender::bke::subdiv
CustomData interface, see also DNA_customdata_types.h.
const void * CustomData_get_layer_n(const CustomData *data, eCustomDataType type, int n)
int CustomData_number_of_layers(const CustomData *data, eCustomDataType type)
UvVertMap * BKE_mesh_uv_vert_map_create(blender::OffsetIndices< int > faces, const bool *hide_poly, const bool *select_poly, const int *corner_verts, const float(*mloopuv)[2], unsigned int totvert, const float limit[2], bool selected, bool use_winding)
void BKE_mesh_uv_vert_map_free(UvVertMap *vmap)
UvMapVert * BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v)
#define STD_UV_CONNECT_LIMIT
@ CD_PROP_FLOAT2
Read Guarded memory(de)allocation.
for(;discarded_id_iter !=nullptr;discarded_id_iter=static_cast< ID * >(discarded_id_iter->next))
Definition blendfile.cc:634
constexpr const T * data() const
Definition BLI_span.hh:215
constexpr bool is_empty() const
Definition BLI_span.hh:260
constexpr int64_t size() const
constexpr int64_t start() const
void resize(const int64_t new_size_in_bits, const bool value=false)
GAttributeReader lookup(const StringRef attribute_id) const
static ushort indices[]
#define MEM_SAFE_FREE(v)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static void init_functions(OpenSubdiv_Converter *converter)
static void free_user_data(const OpenSubdiv_Converter *converter)
void converter_init_for_mesh(OpenSubdiv_Converter *converter, const Settings *settings, const Mesh *mesh)
BLI_INLINE float crease_to_sharpness(float crease)
static int get_num_uvs(const OpenSubdiv_Converter *converter)
static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter, int manifold_vertex_index)
static void get_face_vertices(const OpenSubdiv_Converter *converter, int manifold_face_index, int *manifold_face_vertices)
int converter_fvar_linear_from_settings(const Settings *settings)
static float get_edge_sharpness(const OpenSubdiv_Converter *converter, int manifold_edge_index)
static int get_num_uv_layers(const OpenSubdiv_Converter *converter)
static OpenSubdiv_SchemeType get_scheme_type(const OpenSubdiv_Converter *converter)
static bool specifies_full_topology(const OpenSubdiv_Converter *)
static void finish_uv_layer(const OpenSubdiv_Converter *)
int converter_vtx_boundary_interpolation_from_settings(const Settings *settings)
static float get_vertex_sharpness(const OpenSubdiv_Converter *converter, int manifold_vertex_index)
static void initialize_manifold_index_array(const BitSpan not_used_map, const int num_elements, int **r_indices, int **r_indices_reverse, int *r_num_manifold_elements)
static int get_num_vertices(const OpenSubdiv_Converter *converter)
static int get_num_edges(const OpenSubdiv_Converter *converter)
static int get_face_corner_uv_index(const OpenSubdiv_Converter *converter, const int face_index, const int corner)
static OpenSubdiv_FVarLinearInterpolation get_fvar_linear_interpolation(const OpenSubdiv_Converter *converter)
static void precalc_uv_layer(const OpenSubdiv_Converter *converter, const int layer_index)
static OpenSubdiv_VtxBoundaryInterpolation get_vtx_boundary_interpolation(const OpenSubdiv_Converter *converter)
static void init_user_data(OpenSubdiv_Converter *converter, const Settings *settings, const Mesh *mesh)
static void initialize_manifold_indices(ConverterStorage *storage)
static void get_edge_vertices(const OpenSubdiv_Converter *converter, int manifold_edge_index, int *manifold_edge_vertices)
VecBase< int32_t, 2 > int2
OpenSubdiv_FVarLinearInterpolation
OpenSubdiv_VtxBoundaryInterpolation
OpenSubdiv_SchemeType
@ OSD_SCHEME_CATMARK
@ OSD_SCHEME_BILINEAR
int(* getFaceCornerUVIndex)(const OpenSubdiv_Converter *converter, const int face_index, const int corner_index)
void(* freeUserData)(const OpenSubdiv_Converter *converter)
int(* getNumEdges)(const OpenSubdiv_Converter *converter)
void(* precalcUVLayer)(const OpenSubdiv_Converter *converter, const int layer_index)
float(* getEdgeSharpness)(const OpenSubdiv_Converter *converter, const int edge_index)
int(* getNumVertexFaces)(const OpenSubdiv_Converter *converter, const int vertex_index)
void(* getVertexFaces)(const OpenSubdiv_Converter *converter, const int vertex_index, int *vertex_faces)
void(* getVertexEdges)(const OpenSubdiv_Converter *converter, const int vertex_index, int *vertex_edges)
OpenSubdiv_FVarLinearInterpolation(* getFVarLinearInterpolation)(const OpenSubdiv_Converter *converter)
bool(* specifiesFullTopology)(const OpenSubdiv_Converter *converter)
int(* getNumUVCoordinates)(const OpenSubdiv_Converter *converter)
void(* getFaceVertices)(const OpenSubdiv_Converter *converter, const int face_index, int *face_vertices)
OpenSubdiv_VtxBoundaryInterpolation(* getVtxBoundaryInterpolation)(const OpenSubdiv_Converter *converter)
int(* getNumUVLayers)(const OpenSubdiv_Converter *converter)
int(* getNumEdgeFaces)(const OpenSubdiv_Converter *converter, const int edge_index)
blender::OffsetIndices< int > faces
bool(* isInfiniteSharpVertex)(const OpenSubdiv_Converter *converter, const int vertex_index)
float(* getVertexSharpness)(const OpenSubdiv_Converter *converter, const int vertex_index)
OpenSubdiv_SchemeType(* getSchemeType)(const OpenSubdiv_Converter *converter)
void(* getEdgeVertices)(const OpenSubdiv_Converter *converter, const int edge_index, int edge_vertices[2])
int(* getNumVertexEdges)(const OpenSubdiv_Converter *converter, const int vertex_index)
int(* getNumVertices)(const OpenSubdiv_Converter *converter)
void(* getFaceEdges)(const OpenSubdiv_Converter *converter, const int face_index, int *face_edges)
void(* finishUVLayer)(const OpenSubdiv_Converter *converter)
void(* getEdgeFaces)(const OpenSubdiv_Converter *converter, const int edge, int *edge_faces)
unsigned int face_index
UvMapVert * next
unsigned short loop_of_face_index
blender::BitVector is_loose_bits
i
Definition text_draw.cc:230