Blender V4.3
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
9#include "subdiv_converter.hh"
10
11#include <cstring>
12
13#include "BLI_utildefines.h"
14
15#include "BKE_attribute.hh"
16#include "BKE_customdata.hh"
17#include "BKE_mesh.hh"
18#include "BKE_mesh_mapping.hh"
19#include "BKE_subdiv.hh"
20
21#include "MEM_guardedalloc.h"
22
24
25namespace blender::bke::subdiv {
26
27/* Enable work-around for non-working CPU evaluator when using bilinear scheme.
28 * This forces Catmark scheme with all edges marked as infinitely sharp. */
29#define BUGGY_SIMPLE_SCHEME_WORKAROUND 1
30
33 const Mesh *mesh;
39
40 /* CustomData layer for vertex sharpnesses. */
42 /* CustomData layer for edge sharpness. */
44 /* Indexed by loop index, value denotes index of face-varying vertex
45 * which corresponds to the UV coordinate.
46 */
49 /* Indexed by coarse mesh elements, gives index of corresponding element
50 * with ignoring all non-manifold entities.
51 *
52 * NOTE: This isn't strictly speaking manifold, this is more like non-loose
53 * geometry index. As in, index of element as if there were no loose edges
54 * or vertices in the mesh.
55 */
57 /* Indexed by vertex index from mesh, corresponds to whether this vertex has
58 * infinite sharpness due to non-manifold topology.
59 */
61 /* Reverse mapping to above. */
64 /* Number of non-loose elements. */
67};
68
70{
71#if BUGGY_SIMPLE_SCHEME_WORKAROUND
72 (void)converter;
73 return OSD_SCHEME_CATMARK;
74#else
75 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
76 if (storage->settings.is_simple) {
78 }
79 else {
80 return OSD_SCHEME_CATMARK;
81 }
82#endif
83}
84
92
100
101static bool specifies_full_topology(const OpenSubdiv_Converter * /*converter*/)
102{
103 return false;
104}
105
106static int get_num_faces(const OpenSubdiv_Converter *converter)
107{
108 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
109 return storage->mesh->faces_num;
110}
111
112static int get_num_edges(const OpenSubdiv_Converter *converter)
113{
114 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
115 return storage->num_manifold_edges;
116}
117
118static int get_num_vertices(const OpenSubdiv_Converter *converter)
119{
120 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
121 return storage->num_manifold_vertices;
122}
123
124static int get_num_face_vertices(const OpenSubdiv_Converter *converter, int manifold_face_index)
125{
126 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
127 return storage->faces[manifold_face_index].size();
128}
129
130static void get_face_vertices(const OpenSubdiv_Converter *converter,
131 int manifold_face_index,
132 int *manifold_face_vertices)
133{
134 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
135 const IndexRange face = storage->faces[manifold_face_index];
136 for (int i = 0; i < face.size(); i++) {
137 const int vert = storage->corner_verts[face[i]];
138 manifold_face_vertices[i] = storage->manifold_vertex_index[vert];
139 }
140}
141
142static void get_edge_vertices(const OpenSubdiv_Converter *converter,
143 int manifold_edge_index,
144 int *manifold_edge_vertices)
145{
146 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
147 const int edge_index = storage->manifold_edge_index_reverse[manifold_edge_index];
148 const int2 &edge = storage->edges[edge_index];
149 manifold_edge_vertices[0] = storage->manifold_vertex_index[edge[0]];
150 manifold_edge_vertices[1] = storage->manifold_vertex_index[edge[1]];
151}
152
153static float get_edge_sharpness(const OpenSubdiv_Converter *converter, int manifold_edge_index)
154{
155 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
156#if BUGGY_SIMPLE_SCHEME_WORKAROUND
157 if (storage->settings.is_simple) {
158 return 10.0f;
159 }
160#endif
161 if (storage->cd_edge_crease.is_empty()) {
162 return 0.0f;
163 }
164 const int edge_index = storage->manifold_edge_index_reverse[manifold_edge_index];
165 return crease_to_sharpness(storage->cd_edge_crease[edge_index]);
166}
167
169 int manifold_vertex_index)
170{
171 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
172#if BUGGY_SIMPLE_SCHEME_WORKAROUND
173 if (storage->settings.is_simple) {
174 return true;
175 }
176#endif
177 if (storage->infinite_sharp_vertices_map.is_empty()) {
178 return false;
179 }
180 const int vertex_index = storage->manifold_vertex_index_reverse[manifold_vertex_index];
181 return storage->infinite_sharp_vertices_map[vertex_index];
182}
183
184static float get_vertex_sharpness(const OpenSubdiv_Converter *converter, int manifold_vertex_index)
185{
186 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
187 if (storage->cd_vertex_crease.is_empty()) {
188 return 0.0f;
189 }
190 const int vertex_index = storage->manifold_vertex_index_reverse[manifold_vertex_index];
191 return crease_to_sharpness(storage->cd_vertex_crease[vertex_index]);
192}
193
194static int get_num_uv_layers(const OpenSubdiv_Converter *converter)
195{
196 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
197 const Mesh *mesh = storage->mesh;
198 return CustomData_number_of_layers(&mesh->corner_data, CD_PROP_FLOAT2);
199}
200
201static void precalc_uv_layer(const OpenSubdiv_Converter *converter, const int layer_index)
202{
203 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
204 const Mesh *mesh = storage->mesh;
205 const float(*mloopuv)[2] = static_cast<const float(*)[2]>(
206 CustomData_get_layer_n(&mesh->corner_data, CD_PROP_FLOAT2, layer_index));
207 const int num_vert = mesh->verts_num;
208 const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
209 /* Initialize memory required for the operations. */
210 if (storage->loop_uv_indices == nullptr) {
211 storage->loop_uv_indices = static_cast<int *>(
212 MEM_malloc_arrayN(mesh->corners_num, sizeof(int), "loop uv vertex index"));
213 }
214 UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(storage->faces,
215 nullptr,
216 nullptr,
217 storage->corner_verts.data(),
218 mloopuv,
219 num_vert,
220 limit,
221 false,
222 true);
223 /* NOTE: First UV vertex is supposed to be always marked as separate. */
224 storage->num_uv_coordinates = -1;
225 for (int vertex_index = 0; vertex_index < num_vert; vertex_index++) {
226 const UvMapVert *uv_vert = BKE_mesh_uv_vert_map_get_vert(uv_vert_map, vertex_index);
227 while (uv_vert != nullptr) {
228 if (uv_vert->separate) {
229 storage->num_uv_coordinates++;
230 }
231 const IndexRange face = storage->faces[uv_vert->face_index];
232 const int global_loop_index = face.start() + uv_vert->loop_of_face_index;
233 storage->loop_uv_indices[global_loop_index] = storage->num_uv_coordinates;
234 uv_vert = uv_vert->next;
235 }
236 }
237 /* So far this value was used as a 0-based index, actual number of UV
238 * vertices is 1 more.
239 */
240 storage->num_uv_coordinates += 1;
241 BKE_mesh_uv_vert_map_free(uv_vert_map);
242}
243
244static void finish_uv_layer(const OpenSubdiv_Converter * /*converter*/) {}
245
246static int get_num_uvs(const OpenSubdiv_Converter *converter)
247{
248 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
249 return storage->num_uv_coordinates;
250}
251
253 const int face_index,
254 const int corner)
255{
256 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
257 const IndexRange face = storage->faces[face_index];
258 return storage->loop_uv_indices[face.start() + corner];
259}
260
261static void free_user_data(const OpenSubdiv_Converter *converter)
262{
263 ConverterStorage *user_data = static_cast<ConverterStorage *>(converter->user_data);
264 MEM_SAFE_FREE(user_data->loop_uv_indices);
268 MEM_delete(user_data);
269}
270
272{
273 converter->getSchemeType = get_scheme_type;
277
278 converter->getNumFaces = get_num_faces;
279 converter->getNumEdges = get_num_edges;
280 converter->getNumVertices = get_num_vertices;
281
284 converter->getFaceEdges = nullptr;
285
287 converter->getNumEdgeFaces = nullptr;
288 converter->getEdgeFaces = nullptr;
290
291 converter->getNumVertexEdges = nullptr;
292 converter->getVertexEdges = nullptr;
293 converter->getNumVertexFaces = nullptr;
294 converter->getVertexFaces = nullptr;
297
299 converter->precalcUVLayer = precalc_uv_layer;
300 converter->finishUVLayer = finish_uv_layer;
301 converter->getNumUVCoordinates = get_num_uvs;
303
304 converter->freeUserData = free_user_data;
305}
306
307static void initialize_manifold_index_array(const BitSpan not_used_map,
308 const int num_elements,
309 int **r_indices,
310 int **r_indices_reverse,
311 int *r_num_manifold_elements)
312{
313 int *indices = nullptr;
314 if (r_indices != nullptr) {
315 indices = static_cast<int *>(MEM_malloc_arrayN(num_elements, sizeof(int), "manifold indices"));
316 }
317 int *indices_reverse = nullptr;
318 if (r_indices_reverse != nullptr) {
319 indices_reverse = static_cast<int *>(
320 MEM_malloc_arrayN(num_elements, sizeof(int), "manifold indices reverse"));
321 }
322 int offset = 0;
323 for (int i = 0; i < num_elements; i++) {
324 if (not_used_map.is_empty() || !not_used_map[i]) {
325 if (indices != nullptr) {
326 indices[i] = i - offset;
327 }
328 if (indices_reverse != nullptr) {
329 indices_reverse[i - offset] = i;
330 }
331 }
332 else {
333 if (indices != nullptr) {
334 indices[i] = -1;
335 }
336 offset++;
337 }
338 }
339 if (r_indices != nullptr) {
340 *r_indices = indices;
341 }
342 if (r_indices_reverse != nullptr) {
343 *r_indices_reverse = indices_reverse;
344 }
345 *r_num_manifold_elements = num_elements - offset;
346}
347
349{
350 const Mesh *mesh = storage->mesh;
351 const bke::LooseVertCache &loose_verts = mesh->verts_no_face();
352 const bke::LooseEdgeCache &loose_edges = mesh->loose_edges();
354 mesh->verts_num,
355 &storage->manifold_vertex_index,
357 &storage->num_manifold_vertices);
359 mesh->edges_num,
360 nullptr,
362 &storage->num_manifold_edges);
363 /* Initialize infinite sharp mapping. */
364 if (loose_edges.count > 0) {
365 const Span<int2> edges = storage->edges;
366 storage->infinite_sharp_vertices_map.resize(mesh->verts_num, false);
367 for (int edge_index = 0; edge_index < mesh->edges_num; edge_index++) {
368 if (loose_edges.is_loose_bits[edge_index]) {
369 const int2 edge = edges[edge_index];
370 storage->infinite_sharp_vertices_map[edge[0]].set();
371 storage->infinite_sharp_vertices_map[edge[1]].set();
372 }
373 }
374 }
375}
376
378 const Settings *settings,
379 const Mesh *mesh)
380{
381 ConverterStorage *user_data = MEM_new<ConverterStorage>(__func__);
382 user_data->settings = *settings;
383 user_data->mesh = mesh;
384 user_data->vert_positions = mesh->vert_positions();
385 user_data->edges = mesh->edges();
386 user_data->faces = mesh->faces();
387 user_data->corner_verts = mesh->corner_verts();
388 user_data->corner_edges = mesh->corner_edges();
389 if (settings->use_creases) {
390 const AttributeAccessor attributes = mesh->attributes();
391 user_data->cd_vertex_crease = *attributes.lookup<float>("crease_vert", AttrDomain::Point);
392 user_data->cd_edge_crease = *attributes.lookup<float>("crease_edge", AttrDomain::Edge);
393 }
394 user_data->loop_uv_indices = nullptr;
396 converter->user_data = user_data;
397}
398
400 const Settings *settings,
401 const Mesh *mesh)
402{
403 init_functions(converter);
404 init_user_data(converter, settings, mesh);
405}
406
407} // 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.
#define MEM_SAFE_FREE(v)
constexpr const T * data() const
Definition BLI_span.hh:216
constexpr bool is_empty() const
Definition BLI_span.hh:261
void resize(const int64_t new_size_in_bits, const bool value=false)
draw_view in_light_buf[] float
static ushort indices[]
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
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)
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 int get_num_face_vertices(const OpenSubdiv_Converter *converter, int manifold_face_index)
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)
BLI_INLINE float crease_to_sharpness(float edge_crease)
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 int get_num_faces(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)
OpenSubdiv_FVarLinearInterpolation
OpenSubdiv_VtxBoundaryInterpolation
OpenSubdiv_SchemeType
@ OSD_SCHEME_CATMARK
@ OSD_SCHEME_BILINEAR
int faces_num
int verts_num
int(* getFaceCornerUVIndex)(const OpenSubdiv_Converter *converter, const int face_index, const int corner_index)
int(* getNumFaceVertices)(const OpenSubdiv_Converter *converter, const int face_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)
int(* getNumFaces)(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)
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