Blender V5.0
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 bke::AttributeAccessor attributes = mesh->attributes();
193 &mesh->corner_data, CD_PROP_FLOAT2, layer_index);
194 const VArraySpan uv_map = *attributes.lookup<float2>(name, bke::AttrDomain::Corner);
195 const int num_vert = mesh->verts_num;
196 /* Initialize memory required for the operations. */
197 if (storage->loop_uv_indices == nullptr) {
198 storage->loop_uv_indices = MEM_malloc_arrayN<int>(size_t(mesh->corners_num),
199 "loop uv vertex index");
200 }
201 UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(storage->faces,
202 storage->corner_verts,
203 uv_map,
204 num_vert,
206 true);
207 /* NOTE: First UV vertex is supposed to be always marked as separate. */
208 storage->num_uv_coordinates = -1;
209 for (int vertex_index = 0; vertex_index < num_vert; vertex_index++) {
210 const UvMapVert *uv_vert = BKE_mesh_uv_vert_map_get_vert(uv_vert_map, vertex_index);
211 while (uv_vert != nullptr) {
212 if (uv_vert->separate) {
213 storage->num_uv_coordinates++;
214 }
215 const IndexRange face = storage->faces[uv_vert->face_index];
216 const int global_loop_index = face.start() + uv_vert->loop_of_face_index;
217 storage->loop_uv_indices[global_loop_index] = storage->num_uv_coordinates;
218 uv_vert = uv_vert->next;
219 }
220 }
221 /* So far this value was used as a 0-based index, actual number of UV
222 * vertices is 1 more.
223 */
224 storage->num_uv_coordinates += 1;
225 BKE_mesh_uv_vert_map_free(uv_vert_map);
226}
227
228static void finish_uv_layer(const OpenSubdiv_Converter * /*converter*/) {}
229
230static int get_num_uvs(const OpenSubdiv_Converter *converter)
231{
232 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
233 return storage->num_uv_coordinates;
234}
235
237 const int face_index,
238 const int corner)
239{
240 ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
241 const IndexRange face = storage->faces[face_index];
242 return storage->loop_uv_indices[face.start() + corner];
243}
244
245static void free_user_data(const OpenSubdiv_Converter *converter)
246{
247 ConverterStorage *user_data = static_cast<ConverterStorage *>(converter->user_data);
248 MEM_SAFE_FREE(user_data->loop_uv_indices);
252 MEM_delete(user_data);
253}
254
256{
257 converter->getSchemeType = get_scheme_type;
261
262 converter->getNumEdges = get_num_edges;
263 converter->getNumVertices = get_num_vertices;
264
266 converter->getFaceEdges = nullptr;
267
269 converter->getNumEdgeFaces = nullptr;
270 converter->getEdgeFaces = nullptr;
272
273 converter->getNumVertexEdges = nullptr;
274 converter->getVertexEdges = nullptr;
275 converter->getNumVertexFaces = nullptr;
276 converter->getVertexFaces = nullptr;
279
281 converter->precalcUVLayer = precalc_uv_layer;
282 converter->finishUVLayer = finish_uv_layer;
283 converter->getNumUVCoordinates = get_num_uvs;
285
286 converter->freeUserData = free_user_data;
287}
288
289static void initialize_manifold_index_array(const BitSpan not_used_map,
290 const int num_elements,
291 int **r_indices,
292 int **r_indices_reverse,
293 int *r_num_manifold_elements)
294{
295 int *indices = nullptr;
296 if (r_indices != nullptr) {
297 indices = MEM_malloc_arrayN<int>(size_t(num_elements), "manifold indices");
298 }
299 int *indices_reverse = nullptr;
300 if (r_indices_reverse != nullptr) {
301 indices_reverse = MEM_malloc_arrayN<int>(size_t(num_elements), "manifold indices reverse");
302 }
303 int offset = 0;
304 for (int i = 0; i < num_elements; i++) {
305 if (not_used_map.is_empty() || !not_used_map[i]) {
306 if (indices != nullptr) {
307 indices[i] = i - offset;
308 }
309 if (indices_reverse != nullptr) {
310 indices_reverse[i - offset] = i;
311 }
312 }
313 else {
314 if (indices != nullptr) {
315 indices[i] = -1;
316 }
317 offset++;
318 }
319 }
320 if (r_indices != nullptr) {
321 *r_indices = indices;
322 }
323 if (r_indices_reverse != nullptr) {
324 *r_indices_reverse = indices_reverse;
325 }
326 *r_num_manifold_elements = num_elements - offset;
327}
328
330{
331 const Mesh *mesh = storage->mesh;
332 const bke::LooseVertCache &loose_verts = mesh->verts_no_face();
333 const bke::LooseEdgeCache &loose_edges = mesh->loose_edges();
335 mesh->verts_num,
336 &storage->manifold_vertex_index,
338 &storage->num_manifold_vertices);
340 mesh->edges_num,
341 nullptr,
343 &storage->num_manifold_edges);
344 /* Initialize infinite sharp mapping. */
345 if (loose_edges.count > 0) {
346 const Span<int2> edges = storage->edges;
347 storage->infinite_sharp_vertices_map.resize(mesh->verts_num, false);
348 for (int edge_index = 0; edge_index < mesh->edges_num; edge_index++) {
349 if (loose_edges.is_loose_bits[edge_index]) {
350 const int2 edge = edges[edge_index];
351 storage->infinite_sharp_vertices_map[edge[0]].set();
352 storage->infinite_sharp_vertices_map[edge[1]].set();
353 }
354 }
355 }
356}
357
359 const Settings *settings,
360 const Mesh *mesh)
361{
362 ConverterStorage *user_data = MEM_new<ConverterStorage>(__func__);
363 user_data->settings = *settings;
364 user_data->mesh = mesh;
365 user_data->vert_positions = mesh->vert_positions();
366 user_data->edges = mesh->edges();
367 user_data->faces = mesh->faces();
368 user_data->corner_verts = mesh->corner_verts();
369 user_data->corner_edges = mesh->corner_edges();
370 if (settings->use_creases) {
371 const AttributeAccessor attributes = mesh->attributes();
372 user_data->cd_vertex_crease = *attributes.lookup<float>("crease_vert", AttrDomain::Point);
373 user_data->cd_edge_crease = *attributes.lookup<float>("crease_edge", AttrDomain::Edge);
374 }
375 user_data->loop_uv_indices = nullptr;
377 converter->user_data = user_data;
378}
379
381 const Settings *settings,
382 const Mesh *mesh)
383{
384 converter->faces = mesh->faces();
385 init_functions(converter);
386 init_user_data(converter, settings, mesh);
387}
388
389} // namespace blender::bke::subdiv
CustomData interface, see also DNA_customdata_types.h.
const char * CustomData_get_layer_name(const CustomData *data, eCustomDataType type, int n)
int CustomData_number_of_layers(const CustomData *data, eCustomDataType type)
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
UvVertMap * BKE_mesh_uv_vert_map_create(blender::OffsetIndices< int > faces, blender::Span< int > corner_verts, blender::Span< blender::float2 > uv_map, int verts_num, const blender::float2 &limit, bool use_winding)
@ CD_PROP_FLOAT2
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
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[]
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
VecBase< float, 2 > float2
OpenSubdiv_FVarLinearInterpolation
OpenSubdiv_VtxBoundaryInterpolation
OpenSubdiv_SchemeType
@ OSD_SCHEME_CATMARK
@ OSD_SCHEME_BILINEAR
const char * name
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