Blender V4.3
subdiv_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 <mutex>
10
11#include "DNA_key_types.h"
12#include "DNA_mesh_types.h"
13
14#include "BLI_array.hh"
15#include "BLI_math_vector.h"
16#include "BLI_math_vector.hh"
18#include "BLI_task.hh"
19
20#include "BKE_attribute_math.hh"
21#include "BKE_customdata.hh"
22#include "BKE_key.hh"
23#include "BKE_mesh.hh"
24#include "BKE_mesh_mapping.hh"
25#include "BKE_subdiv.hh"
26#include "BKE_subdiv_eval.hh"
27#include "BKE_subdiv_foreach.hh"
28#include "BKE_subdiv_mesh.hh"
29
30#include "MEM_guardedalloc.h"
31
32namespace blender::bke::subdiv {
33
34/* -------------------------------------------------------------------- */
45
52
58
65
66 /* Cached custom data arrays for faster access. */
71 /* UV layers interpolation. */
74
75 /* Original coordinates (ORCO) interpolation. */
76 float (*orco)[3];
78 /* Per-subdivided vertex counter of averaged values. */
81
82 /* Write optimal display edge tags into a boolean array rather than the final bit vector
83 * to avoid race conditions when setting bits. */
85
86 /* Lazily initialize a map from vertices to connected edges. */
90};
91
93{
94 Mesh *subdiv_mesh = ctx->subdiv_mesh;
95 ctx->num_uv_layers = std::min(
97 for (int layer_index = 0; layer_index < ctx->num_uv_layers; layer_index++) {
98 ctx->uv_layers[layer_index] = static_cast<float2 *>(CustomData_get_layer_n_for_write(
99 &subdiv_mesh->corner_data, CD_PROP_FLOAT2, layer_index, subdiv_mesh->corners_num));
100 }
101}
102
104{
105 Mesh *subdiv_mesh = ctx->subdiv_mesh;
106 ctx->subdiv_positions = subdiv_mesh->vert_positions_for_write();
107 ctx->subdiv_edges = subdiv_mesh->edges_for_write();
108 ctx->subdiv_face_offsets = subdiv_mesh->face_offsets_for_write();
109 /* Pointers to original indices layers. */
110 ctx->vert_origindex = static_cast<int *>(CustomData_get_layer_for_write(
111 &subdiv_mesh->vert_data, CD_ORIGINDEX, subdiv_mesh->verts_num));
112 ctx->edge_origindex = static_cast<int *>(CustomData_get_layer_for_write(
113 &subdiv_mesh->edge_data, CD_ORIGINDEX, subdiv_mesh->edges_num));
114 ctx->loop_origindex = static_cast<int *>(CustomData_get_layer_for_write(
115 &subdiv_mesh->corner_data, CD_ORIGINDEX, subdiv_mesh->corners_num));
116 ctx->face_origindex = static_cast<int *>(CustomData_get_layer_for_write(
117 &subdiv_mesh->face_data, CD_ORIGINDEX, subdiv_mesh->faces_num));
118 /* UV layers interpolation. */
120 /* Orco interpolation. */
121 ctx->orco = static_cast<float(*)[3]>(
122 CustomData_get_layer_for_write(&subdiv_mesh->vert_data, CD_ORCO, subdiv_mesh->verts_num));
123 ctx->cloth_orco = static_cast<float(*)[3]>(CustomData_get_layer_for_write(
124 &subdiv_mesh->vert_data, CD_CLOTH_ORCO, subdiv_mesh->verts_num));
125}
126
127static void subdiv_mesh_prepare_accumulator(SubdivMeshContext *ctx, int num_vertices)
128{
129 if (!ctx->have_displacement) {
130 return;
131 }
132 ctx->accumulated_counters = static_cast<int *>(
133 MEM_calloc_arrayN(num_vertices, sizeof(*ctx->accumulated_counters), __func__));
134}
135
143
146/* -------------------------------------------------------------------- */
151 /* First loop of the ptex, starts at ptex (0, 0) and goes in u direction. */
153 /* Last loop of the ptex, starts at ptex (0, 0) and goes in v direction. */
155 /* For quad coarse faces only. */
158};
159
160static void loops_of_ptex_get(LoopsOfPtex *loops_of_ptex,
161 const IndexRange coarse_face,
162 const int ptex_of_face_index)
163{
164 const int first_ptex_loop_index = coarse_face.start() + ptex_of_face_index;
165 /* Loop which look in the (opposite) V direction of the current
166 * ptex face.
167 *
168 * TODO(sergey): Get rid of using module on every iteration. */
169 const int last_ptex_loop_index = coarse_face.start() +
170 (ptex_of_face_index + coarse_face.size() - 1) %
171 coarse_face.size();
172 loops_of_ptex->first_loop = first_ptex_loop_index;
173 loops_of_ptex->last_loop = last_ptex_loop_index;
174 if (coarse_face.size() == 4) {
175 loops_of_ptex->second_loop = loops_of_ptex->first_loop + 1;
176 loops_of_ptex->third_loop = loops_of_ptex->first_loop + 2;
177 }
178 else {
179 loops_of_ptex->second_loop = -1;
180 loops_of_ptex->third_loop = -1;
181 }
182}
183
186/* -------------------------------------------------------------------- */
190/* TODO(sergey): Somehow de-duplicate with loops storage, without too much
191 * exception cases all over the code. */
192
194 /* This field points to a vertex data which is to be used for interpolation.
195 * The idea is to avoid unnecessary allocations for regular faces, where
196 * we can simply use corner vertices. */
198 /* Vertices data calculated for ptex corners. There are always 4 elements
199 * in this custom data, aligned the following way:
200 *
201 * index 0 -> uv (0, 0)
202 * index 1 -> uv (0, 1)
203 * index 2 -> uv (1, 1)
204 * index 3 -> uv (1, 0)
205 *
206 * Is allocated for non-regular faces (triangles and n-gons). */
209 /* Indices within vertex_data to interpolate for. The indices are aligned
210 * with uv coordinates in a similar way as indices in corner_data_storage. */
212};
213
215 VerticesForInterpolation *vertex_interpolation,
216 const IndexRange coarse_face)
217{
218 const Mesh *coarse_mesh = ctx->coarse_mesh;
219 if (coarse_face.size() == 4) {
220 vertex_interpolation->vertex_data = &coarse_mesh->vert_data;
221 vertex_interpolation->vertex_indices[0] = ctx->coarse_corner_verts[coarse_face.start() + 0];
222 vertex_interpolation->vertex_indices[1] = ctx->coarse_corner_verts[coarse_face.start() + 1];
223 vertex_interpolation->vertex_indices[2] = ctx->coarse_corner_verts[coarse_face.start() + 2];
224 vertex_interpolation->vertex_indices[3] = ctx->coarse_corner_verts[coarse_face.start() + 3];
225 vertex_interpolation->vertex_data_storage_allocated = false;
226 }
227 else {
228 vertex_interpolation->vertex_data = &vertex_interpolation->vertex_data_storage;
229 /* Allocate storage for loops corresponding to ptex corners. */
231 &vertex_interpolation->vertex_data_storage,
234 4);
235 /* Initialize indices. */
236 vertex_interpolation->vertex_indices[0] = 0;
237 vertex_interpolation->vertex_indices[1] = 1;
238 vertex_interpolation->vertex_indices[2] = 2;
239 vertex_interpolation->vertex_indices[3] = 3;
240 vertex_interpolation->vertex_data_storage_allocated = true;
241 /* Interpolate center of face right away, it stays unchanged for all
242 * ptex faces. */
243 const float weight = 1.0f / float(coarse_face.size());
244 Array<float, 32> weights(coarse_face.size());
245 Array<int, 32> indices(coarse_face.size());
246 for (int i = 0; i < coarse_face.size(); i++) {
247 weights[i] = weight;
248 indices[i] = ctx->coarse_corner_verts[coarse_face.start() + i];
249 }
250 CustomData_interp(&coarse_mesh->vert_data,
251 &vertex_interpolation->vertex_data_storage,
252 indices.data(),
253 weights.data(),
254 nullptr,
255 coarse_face.size(),
256 2);
257 }
258}
259
261 VerticesForInterpolation *vertex_interpolation,
262 const IndexRange coarse_face,
263 const int corner)
264{
265 if (coarse_face.size() == 4) {
266 /* Nothing to do, all indices and data is already assigned. */
267 }
268 else {
269 const CustomData *vertex_data = &ctx->coarse_mesh->vert_data;
270 LoopsOfPtex loops_of_ptex;
271 loops_of_ptex_get(&loops_of_ptex, coarse_face, corner);
272 /* PTEX face corner corresponds to a face loop with same index. */
273 CustomData_copy_data(vertex_data,
274 &vertex_interpolation->vertex_data_storage,
275 ctx->coarse_corner_verts[coarse_face.start() + corner],
276 0,
277 1);
278 /* Interpolate remaining ptex face corners, which hits loops
279 * middle points.
280 *
281 * TODO(sergey): Re-use one of interpolation results from previous
282 * iteration. */
283 const float weights[2] = {0.5f, 0.5f};
284 const int first_loop_index = loops_of_ptex.first_loop;
285 const int last_loop_index = loops_of_ptex.last_loop;
286 const int first_indices[2] = {
287 ctx->coarse_corner_verts[first_loop_index],
288 ctx->coarse_corner_verts[coarse_face.start() +
289 (first_loop_index - coarse_face.start() + 1) %
290 coarse_face.size()]};
291 const int last_indices[2] = {ctx->coarse_corner_verts[first_loop_index],
292 ctx->coarse_corner_verts[last_loop_index]};
293 CustomData_interp(vertex_data,
294 &vertex_interpolation->vertex_data_storage,
295 first_indices,
296 weights,
297 nullptr,
298 2,
299 1);
300 CustomData_interp(vertex_data,
301 &vertex_interpolation->vertex_data_storage,
302 last_indices,
303 weights,
304 nullptr,
305 2,
306 3);
307 }
308}
309
310static void vertex_interpolation_end(VerticesForInterpolation *vertex_interpolation)
311{
312 if (vertex_interpolation->vertex_data_storage_allocated) {
313 CustomData_free(&vertex_interpolation->vertex_data_storage, 4);
314 }
315}
316
319/* -------------------------------------------------------------------- */
324 /* This field points to a loop data which is to be used for interpolation.
325 * The idea is to avoid unnecessary allocations for regular faces, where
326 * we can simply interpolate corner vertices. */
328 /* Loops data calculated for ptex corners. There are always 4 elements
329 * in this custom data, aligned the following way:
330 *
331 * index 0 -> uv (0, 0)
332 * index 1 -> uv (0, 1)
333 * index 2 -> uv (1, 1)
334 * index 3 -> uv (1, 0)
335 *
336 * Is allocated for non-regular faces (triangles and n-gons). */
339 /* Indices within corner_data to interpolate for. The indices are aligned with
340 * uv coordinates in a similar way as indices in corner_data_storage. */
342};
343
345 LoopsForInterpolation *loop_interpolation,
346 const IndexRange coarse_face)
347{
348 if (coarse_face.size() == 4) {
349 loop_interpolation->corner_data = &ctx->coarse_corner_data_interp;
350 loop_interpolation->loop_indices[0] = coarse_face.start() + 0;
351 loop_interpolation->loop_indices[1] = coarse_face.start() + 1;
352 loop_interpolation->loop_indices[2] = coarse_face.start() + 2;
353 loop_interpolation->loop_indices[3] = coarse_face.start() + 3;
354 loop_interpolation->corner_data_storage_allocated = false;
355 }
356 else {
357 loop_interpolation->corner_data = &loop_interpolation->corner_data_storage;
358 /* Allocate storage for loops corresponding to ptex corners. */
360 &loop_interpolation->corner_data_storage,
363 4);
364 /* Initialize indices. */
365 loop_interpolation->loop_indices[0] = 0;
366 loop_interpolation->loop_indices[1] = 1;
367 loop_interpolation->loop_indices[2] = 2;
368 loop_interpolation->loop_indices[3] = 3;
369 loop_interpolation->corner_data_storage_allocated = true;
370 /* Interpolate center of face right away, it stays unchanged for all
371 * ptex faces. */
372 const float weight = 1.0f / float(coarse_face.size());
373 Array<float, 32> weights(coarse_face.size());
374 Array<int, 32> indices(coarse_face.size());
375 for (int i = 0; i < coarse_face.size(); i++) {
376 weights[i] = weight;
377 indices[i] = coarse_face.start() + i;
378 }
380 &loop_interpolation->corner_data_storage,
381 indices.data(),
382 weights.data(),
383 nullptr,
384 coarse_face.size(),
385 2);
386 }
387}
388
390 LoopsForInterpolation *loop_interpolation,
391 const IndexRange coarse_face,
392 const int corner)
393{
394 if (coarse_face.size() == 4) {
395 /* Nothing to do, all indices and data is already assigned. */
396 }
397 else {
398 const CustomData *corner_data = &ctx->coarse_corner_data_interp;
399 LoopsOfPtex loops_of_ptex;
400 loops_of_ptex_get(&loops_of_ptex, coarse_face, corner);
401 /* PTEX face corner corresponds to a face loop with same index. */
402 CustomData_free_elem(&loop_interpolation->corner_data_storage, 0, 1);
404 corner_data, &loop_interpolation->corner_data_storage, coarse_face.start() + corner, 0, 1);
405 /* Interpolate remaining ptex face corners, which hits loops
406 * middle points.
407 *
408 * TODO(sergey): Re-use one of interpolation results from previous
409 * iteration. */
410 const float weights[2] = {0.5f, 0.5f};
411 const int base_loop_index = coarse_face.start();
412 const int first_loop_index = loops_of_ptex.first_loop;
413 const int second_loop_index = base_loop_index +
414 (first_loop_index - base_loop_index + 1) % coarse_face.size();
415 const int first_indices[2] = {first_loop_index, second_loop_index};
416 const int last_indices[2] = {loops_of_ptex.last_loop, loops_of_ptex.first_loop};
417 CustomData_interp(corner_data,
418 &loop_interpolation->corner_data_storage,
419 first_indices,
420 weights,
421 nullptr,
422 2,
423 1);
424 CustomData_interp(corner_data,
425 &loop_interpolation->corner_data_storage,
426 last_indices,
427 weights,
428 nullptr,
429 2,
430 3);
431 }
432}
433
434static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation)
435{
436 if (loop_interpolation->corner_data_storage_allocated) {
437 CustomData_free(&loop_interpolation->corner_data_storage, 4);
438 }
439}
440
443/* -------------------------------------------------------------------- */
458
459static void subdiv_mesh_tls_free(void *tls_v)
460{
461 SubdivMeshTLS *tls = static_cast<SubdivMeshTLS *>(tls_v);
464 }
467 }
468}
469
472/* -------------------------------------------------------------------- */
477 const int ptex_face_index,
478 const float u,
479 const float v,
480 const int subdiv_vertex_index)
481{
482 if (ctx->orco || ctx->cloth_orco) {
483 float vertex_data[6];
484 eval_vertex_data(ctx->subdiv, ptex_face_index, u, v, vertex_data);
485
486 if (ctx->orco) {
487 copy_v3_v3(ctx->orco[subdiv_vertex_index], vertex_data);
488 if (ctx->cloth_orco) {
489 copy_v3_v3(ctx->cloth_orco[subdiv_vertex_index], vertex_data + 3);
490 }
491 }
492 else if (ctx->cloth_orco) {
493 copy_v3_v3(ctx->cloth_orco[subdiv_vertex_index], vertex_data);
494 }
495 }
496}
497
500/* -------------------------------------------------------------------- */
505 const int ptex_face_index,
506 const float u,
507 const float v,
508 const int subdiv_vertex_index)
509{
510 /* Accumulate displacement. */
511 Subdiv *subdiv = ctx->subdiv;
512 float dummy_P[3], dPdu[3], dPdv[3], D[3];
513 eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
514
515 /* NOTE: The subdivided mesh is allocated in this module, and its vertices are kept at zero
516 * locations as a default calloc(). */
517 eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
518 ctx->subdiv_positions[subdiv_vertex_index] += D;
519
520 if (ctx->accumulated_counters) {
521 ++ctx->accumulated_counters[subdiv_vertex_index];
522 }
523}
524
527/* -------------------------------------------------------------------- */
531static bool subdiv_mesh_topology_info(const ForeachContext *foreach_context,
532 const int num_vertices,
533 const int num_edges,
534 const int num_loops,
535 const int num_faces,
536 const int * /*subdiv_face_offset*/)
537{
538 /* Multi-resolution grid data will be applied or become invalid after subdivision,
539 * so don't try to preserve it and use memory. Crease values should also not be interpolated. */
541 mask.lmask &= ~CD_MASK_MULTIRES_GRIDS;
542
543 SubdivMeshContext *subdiv_context = static_cast<SubdivMeshContext *>(foreach_context->user_data);
544
545 const Mesh &coarse_mesh = *subdiv_context->coarse_mesh;
547 num_vertices, num_edges, num_faces, num_loops);
548 Mesh &subdiv_mesh = *subdiv_context->subdiv_mesh;
549 BKE_mesh_copy_parameters_for_eval(subdiv_context->subdiv_mesh, &coarse_mesh);
550
551 CustomData_free(&subdiv_mesh.vert_data, 0);
553 &coarse_mesh.vert_data, &subdiv_mesh.vert_data, mask.vmask, CD_SET_DEFAULT, num_vertices);
554 CustomData_free(&subdiv_mesh.edge_data, 0);
556 &coarse_mesh.edge_data, &subdiv_mesh.edge_data, mask.emask, CD_SET_DEFAULT, num_edges);
557 CustomData_free(&subdiv_mesh.face_data, 0);
559 &coarse_mesh.face_data, &subdiv_mesh.face_data, mask.pmask, CD_SET_DEFAULT, num_faces);
560 if (num_faces != 0) {
561 subdiv_mesh.face_offsets_for_write().last() = num_loops;
562 }
563
564 /* Create corner data for interpolation without topology attributes. */
566 &subdiv_context->coarse_corner_data_interp,
567 mask.lmask,
568 coarse_mesh.corners_num);
570 &subdiv_context->coarse_corner_data_interp, ".corner_vert", coarse_mesh.corners_num);
572 &subdiv_context->coarse_corner_data_interp, ".corner_edge", coarse_mesh.corners_num);
573 CustomData_free(&subdiv_mesh.corner_data, 0);
575 &subdiv_mesh.corner_data,
576 mask.lmask,
578 num_loops);
579
580 /* Allocate corner topology arrays which are added to the result at the end. */
581 subdiv_context->subdiv_corner_verts = static_cast<int *>(
582 MEM_malloc_arrayN(num_loops, sizeof(int), __func__));
583 subdiv_context->subdiv_corner_edges = static_cast<int *>(
584 MEM_malloc_arrayN(num_loops, sizeof(int), __func__));
585
587 subdiv_mesh_prepare_accumulator(subdiv_context, num_vertices);
588 subdiv_mesh.runtime->subsurf_face_dot_tags.clear();
589 subdiv_mesh.runtime->subsurf_face_dot_tags.resize(num_vertices);
590 if (subdiv_context->settings->use_optimal_display) {
591 subdiv_context->subdiv_display_edges = Array<bool>(num_edges, false);
592 }
593 return true;
594}
595
598/* -------------------------------------------------------------------- */
603 const int coarse_vertex_index,
604 const int subdiv_vertex_index)
605{
606 const Mesh *coarse_mesh = ctx->coarse_mesh;
607 CustomData_copy_data(&coarse_mesh->vert_data,
608 &ctx->subdiv_mesh->vert_data,
609 coarse_vertex_index,
610 subdiv_vertex_index,
611 1);
612}
613
615 const int subdiv_vertex_index,
616 const VerticesForInterpolation *vertex_interpolation,
617 const float u,
618 const float v)
619{
620 const float weights[4] = {(1.0f - u) * (1.0f - v), u * (1.0f - v), u * v, (1.0f - u) * v};
621 CustomData_interp(vertex_interpolation->vertex_data,
622 &ctx->subdiv_mesh->vert_data,
623 vertex_interpolation->vertex_indices,
624 weights,
625 nullptr,
626 4,
627 subdiv_vertex_index);
628 if (ctx->vert_origindex != nullptr) {
629 ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE;
630 }
631}
632
634 const int ptex_face_index,
635 const float u,
636 const float v,
637 const int coarse_vertex_index,
638 const int subdiv_vertex_index)
639{
640 float3 &subdiv_position = ctx->subdiv_positions[subdiv_vertex_index];
641 /* Displacement is accumulated in subdiv vertex position.
642 * Needs to be backed up before copying data from original vertex. */
643 float D[3] = {0.0f, 0.0f, 0.0f};
644 if (ctx->have_displacement) {
645 const float inv_num_accumulated = 1.0f / ctx->accumulated_counters[subdiv_vertex_index];
646 copy_v3_v3(D, subdiv_position);
647 mul_v3_fl(D, inv_num_accumulated);
648 }
649 /* Copy custom data and evaluate position. */
650 subdiv_vertex_data_copy(ctx, coarse_vertex_index, subdiv_vertex_index);
651 eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_position);
652 /* Apply displacement. */
653 subdiv_position += D;
654 /* Evaluate undeformed texture coordinate. */
655 subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index);
656 /* Remove face-dot flag. This can happen if there is more than one subsurf modifier. */
657 ctx->subdiv_mesh->runtime->subsurf_face_dot_tags[subdiv_vertex_index].reset();
658}
659
661 const SubdivMeshContext *ctx,
662 const int ptex_face_index,
663 const float u,
664 const float v,
665 VerticesForInterpolation *vertex_interpolation,
666 const int subdiv_vertex_index)
667{
668 float3 &subdiv_position = ctx->subdiv_positions[subdiv_vertex_index];
669 /* Displacement is accumulated in subdiv vertex position.
670 * Needs to be backed up before copying data from original vertex. */
671 float D[3] = {0.0f, 0.0f, 0.0f};
672 if (ctx->have_displacement) {
673 const float inv_num_accumulated = 1.0f / ctx->accumulated_counters[subdiv_vertex_index];
674 copy_v3_v3(D, subdiv_position);
675 mul_v3_fl(D, inv_num_accumulated);
676 }
677 /* Interpolate custom data and evaluate position. */
678 subdiv_vertex_data_interpolate(ctx, subdiv_vertex_index, vertex_interpolation, u, v);
679 eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_position);
680 /* Apply displacement. */
681 add_v3_v3(subdiv_position, D);
682 /* Evaluate undeformed texture coordinate. */
683 subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index);
684}
685
687 const ForeachContext *foreach_context,
688 void * /*tls*/,
689 const int ptex_face_index,
690 const float u,
691 const float v,
692 const int subdiv_vertex_index)
693{
694 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
695 subdiv_accumulate_vertex_displacement(ctx, ptex_face_index, u, v, subdiv_vertex_index);
696}
697
699 void *tls,
700 const int ptex_face_index,
701 const float u,
702 const float v,
703 const int /*coarse_vertex_index*/,
704 const int /*coarse_face_index*/,
705 const int /*coarse_corner*/,
706 const int subdiv_vertex_index)
707{
709 foreach_context, tls, ptex_face_index, u, v, subdiv_vertex_index);
710}
711
713 void *tls,
714 const int ptex_face_index,
715 const float u,
716 const float v,
717 const int /*coarse_edge_index*/,
718 const int /*coarse_face_index*/,
719 const int /*coarse_corner*/,
720 const int subdiv_vertex_index)
721{
723 foreach_context, tls, ptex_face_index, u, v, subdiv_vertex_index);
724}
725
726static void subdiv_mesh_vertex_corner(const ForeachContext *foreach_context,
727 void * /*tls*/,
728 const int ptex_face_index,
729 const float u,
730 const float v,
731 const int coarse_vertex_index,
732 const int /*coarse_face_index*/,
733 const int /*coarse_corner*/,
734 const int subdiv_vertex_index)
735{
736 BLI_assert(coarse_vertex_index != ORIGINDEX_NONE);
737 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
739 ctx, ptex_face_index, u, v, coarse_vertex_index, subdiv_vertex_index);
740}
741
743 SubdivMeshTLS *tls,
744 const int coarse_face_index,
745 const int coarse_corner)
746{
747 const IndexRange coarse_face = ctx->coarse_faces[coarse_face_index];
748 /* Check whether we've moved to another corner or face. */
750 if (tls->vertex_interpolation_coarse_face_index != coarse_face_index ||
751 tls->vertex_interpolation_coarse_corner != coarse_corner)
752 {
755 }
756 }
757 /* Initialize the interpolation. */
759 vertex_interpolation_init(ctx, &tls->vertex_interpolation, coarse_face);
760 }
761 /* Update it for a new corner if needed. */
763 tls->vertex_interpolation_coarse_corner != coarse_corner)
764 {
765 vertex_interpolation_from_corner(ctx, &tls->vertex_interpolation, coarse_face, coarse_corner);
766 }
767 /* Store settings used for the current state of interpolator. */
769 tls->vertex_interpolation_coarse_face_index = coarse_face_index;
770 tls->vertex_interpolation_coarse_corner = coarse_corner;
771}
772
773static void subdiv_mesh_vertex_edge(const ForeachContext *foreach_context,
774 void *tls_v,
775 const int ptex_face_index,
776 const float u,
777 const float v,
778 const int /*coarse_edge_index*/,
779 const int coarse_face_index,
780 const int coarse_corner,
781 const int subdiv_vertex_index)
782{
783 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
784 SubdivMeshTLS *tls = static_cast<SubdivMeshTLS *>(tls_v);
785 subdiv_mesh_ensure_vertex_interpolation(ctx, tls, coarse_face_index, coarse_corner);
787 ctx, ptex_face_index, u, v, &tls->vertex_interpolation, subdiv_vertex_index);
788}
789
790static bool subdiv_mesh_is_center_vertex(const IndexRange coarse_face,
791 const float u,
792 const float v)
793{
794 if (coarse_face.size() == 4) {
795 if (u == 0.5f && v == 0.5f) {
796 return true;
797 }
798 }
799 else {
800 if (u == 1.0f && v == 1.0f) {
801 return true;
802 }
803 }
804 return false;
805}
806
807static void subdiv_mesh_tag_center_vertex(const IndexRange coarse_face,
808 const int subdiv_vertex_index,
809 const float u,
810 const float v,
811 Mesh *subdiv_mesh)
812{
813 if (subdiv_mesh_is_center_vertex(coarse_face, u, v)) {
814 subdiv_mesh->runtime->subsurf_face_dot_tags[subdiv_vertex_index].set();
815 }
816}
817
818static void subdiv_mesh_vertex_inner(const ForeachContext *foreach_context,
819 void *tls_v,
820 const int ptex_face_index,
821 const float u,
822 const float v,
823 const int coarse_face_index,
824 const int coarse_corner,
825 const int subdiv_vertex_index)
826{
827 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
828 SubdivMeshTLS *tls = static_cast<SubdivMeshTLS *>(tls_v);
829 Subdiv *subdiv = ctx->subdiv;
830 const IndexRange coarse_face = ctx->coarse_faces[coarse_face_index];
831 Mesh *subdiv_mesh = ctx->subdiv_mesh;
832 float3 &subdiv_position = ctx->subdiv_positions[subdiv_vertex_index];
833 subdiv_mesh_ensure_vertex_interpolation(ctx, tls, coarse_face_index, coarse_corner);
834 subdiv_vertex_data_interpolate(ctx, subdiv_vertex_index, &tls->vertex_interpolation, u, v);
835 eval_final_point(subdiv, ptex_face_index, u, v, subdiv_position);
836 subdiv_mesh_tag_center_vertex(coarse_face, subdiv_vertex_index, u, v, subdiv_mesh);
837 subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index);
838}
839
842/* -------------------------------------------------------------------- */
847 const int subdiv_edge_index,
848 const int coarse_edge_index)
849{
850 if (coarse_edge_index == ORIGINDEX_NONE) {
851 if (ctx->edge_origindex != nullptr) {
852 ctx->edge_origindex[subdiv_edge_index] = ORIGINDEX_NONE;
853 }
854 return;
855 }
857 &ctx->subdiv_mesh->edge_data,
858 coarse_edge_index,
859 subdiv_edge_index,
860 1);
861 if (ctx->settings->use_optimal_display) {
862 ctx->subdiv_display_edges[subdiv_edge_index] = true;
863 }
864}
865
866static void subdiv_mesh_edge(const ForeachContext *foreach_context,
867 void * /*tls*/,
868 const int coarse_edge_index,
869 const int subdiv_edge_index,
870 const bool /*is_loose*/,
871 const int subdiv_v1,
872 const int subdiv_v2)
873{
874 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
875 subdiv_copy_edge_data(ctx, subdiv_edge_index, coarse_edge_index);
876 ctx->subdiv_edges[subdiv_edge_index][0] = subdiv_v1;
877 ctx->subdiv_edges[subdiv_edge_index][1] = subdiv_v2;
878}
879
882/* -------------------------------------------------------------------- */
887 const int subdiv_loop_index,
888 const LoopsForInterpolation *loop_interpolation,
889 const float u,
890 const float v)
891{
892 const float weights[4] = {(1.0f - u) * (1.0f - v), u * (1.0f - v), u * v, (1.0f - u) * v};
893 CustomData_interp(loop_interpolation->corner_data,
895 loop_interpolation->loop_indices,
896 weights,
897 nullptr,
898 4,
899 subdiv_loop_index);
900 /* TODO(sergey): Set ORIGINDEX. */
901}
902
904 const int corner_index,
905 const int ptex_face_index,
906 const float u,
907 const float v)
908{
909 if (ctx->num_uv_layers == 0) {
910 return;
911 }
912 Subdiv *subdiv = ctx->subdiv;
913 for (int layer_index = 0; layer_index < ctx->num_uv_layers; layer_index++) {
915 subdiv, layer_index, ptex_face_index, u, v, ctx->uv_layers[layer_index][corner_index]);
916 }
917}
918
920 SubdivMeshTLS *tls,
921 const int coarse_face_index,
922 const int coarse_corner)
923{
924 const IndexRange coarse_face = ctx->coarse_faces[coarse_face_index];
925 /* Check whether we've moved to another corner or face. */
927 if (tls->loop_interpolation_coarse_face_index != coarse_face_index ||
928 tls->loop_interpolation_coarse_corner != coarse_corner)
929 {
932 }
933 }
934 /* Initialize the interpolation. */
936 loop_interpolation_init(ctx, &tls->loop_interpolation, coarse_face);
937 }
938 /* Update it for a new corner if needed. */
940 tls->loop_interpolation_coarse_corner != coarse_corner)
941 {
942 loop_interpolation_from_corner(ctx, &tls->loop_interpolation, coarse_face, coarse_corner);
943 }
944 /* Store settings used for the current state of interpolator. */
946 tls->loop_interpolation_coarse_face_index = coarse_face_index;
947 tls->loop_interpolation_coarse_corner = coarse_corner;
948}
949
950static void subdiv_mesh_loop(const ForeachContext *foreach_context,
951 void *tls_v,
952 const int ptex_face_index,
953 const float u,
954 const float v,
955 const int /*coarse_loop_index*/,
956 const int coarse_face_index,
957 const int coarse_corner,
958 const int subdiv_loop_index,
959 const int subdiv_vertex_index,
960 const int subdiv_edge_index)
961{
962 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
963 SubdivMeshTLS *tls = static_cast<SubdivMeshTLS *>(tls_v);
964 subdiv_mesh_ensure_loop_interpolation(ctx, tls, coarse_face_index, coarse_corner);
965 subdiv_interpolate_corner_data(ctx, subdiv_loop_index, &tls->loop_interpolation, u, v);
966 subdiv_eval_uv_layer(ctx, subdiv_loop_index, ptex_face_index, u, v);
967 ctx->subdiv_corner_verts[subdiv_loop_index] = subdiv_vertex_index;
968 ctx->subdiv_corner_edges[subdiv_loop_index] = subdiv_edge_index;
969}
970
973/* -------------------------------------------------------------------- */
977static void subdiv_mesh_face(const ForeachContext *foreach_context,
978 void * /*tls*/,
979 const int coarse_face_index,
980 const int subdiv_face_index,
981 const int start_loop_index,
982 const int /*num_loops*/)
983{
984 BLI_assert(coarse_face_index != ORIGINDEX_NONE);
985 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
987 &ctx->subdiv_mesh->face_data,
988 coarse_face_index,
989 subdiv_face_index,
990 1);
991 ctx->subdiv_face_offsets[subdiv_face_index] = start_loop_index;
992}
993
996/* -------------------------------------------------------------------- */
1000static void subdiv_mesh_vertex_loose(const ForeachContext *foreach_context,
1001 void * /*tls*/,
1002 const int coarse_vertex_index,
1003 const int subdiv_vertex_index)
1004{
1005 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
1006 subdiv_vertex_data_copy(ctx, coarse_vertex_index, subdiv_vertex_index);
1007}
1008
1009/* Get neighbor edges of the given one.
1010 * - neighbors[0] is an edge adjacent to edge->v1.
1011 * - neighbors[1] is an edge adjacent to edge->v2. */
1012static std::array<std::optional<int2>, 2> find_edge_neighbors(
1013 const Span<int2> coarse_edges, const GroupedSpan<int> vert_to_edge_map, const int edge_index)
1014{
1015 /* Vertices which has more than one neighbor are considered infinitely
1016 * sharp. This is also how topology factory treats vertices of a surface
1017 * which are adjacent to a loose edge. */
1018 const auto neighbor_edge_if_single = [&](const int vert) -> std::optional<int2> {
1019 const Span<int> neighbors = vert_to_edge_map[vert];
1020 if (neighbors.size() != 2) {
1021 return std::nullopt;
1022 }
1023 return neighbors[0] == edge_index ? coarse_edges[neighbors[1]] : coarse_edges[neighbors[0]];
1024 };
1025 const int2 edge = coarse_edges[edge_index];
1026 return {neighbor_edge_if_single(edge[0]), neighbor_edge_if_single(edge[1])};
1027}
1028
1029static std::array<float3, 4> find_loose_edge_interpolation_positions(
1030 const Span<float3> coarse_positions,
1031 const int2 &coarse_edge,
1032 const std::array<std::optional<int2>, 2> &neighbors)
1033{
1034 std::array<float3, 4> result;
1035 /* Middle points corresponds to the edge. */
1036 result[1] = coarse_positions[coarse_edge[0]];
1037 result[2] = coarse_positions[coarse_edge[1]];
1038 /* Start point, duplicate from edge start if no neighbor. */
1039 if (const std::optional<int2> &other = neighbors[0]) {
1040 result[0] = coarse_positions[mesh::edge_other_vert(*other, coarse_edge[0])];
1041 }
1042 else {
1043 result[0] = result[1] * 2.0f - result[2];
1044 }
1045 /* End point, duplicate from edge end if no neighbor. */
1046 if (const std::optional<int2> &other = neighbors[1]) {
1047 result[3] = coarse_positions[mesh::edge_other_vert(*other, coarse_edge[1])];
1048 }
1049 else {
1050 result[3] = result[2] * 2.0f - result[1];
1051 }
1052 return result;
1053}
1054
1056 const Span<int2> coarse_edges,
1057 const GroupedSpan<int> vert_to_edge_map,
1058 const int coarse_edge_index,
1059 const bool is_simple,
1060 const float u)
1061{
1062 const int2 edge = coarse_edges[coarse_edge_index];
1063 if (is_simple) {
1064 return math::interpolate(coarse_positions[edge[0]], coarse_positions[edge[1]], u);
1065 }
1066 /* Find neighbors of the coarse edge. */
1067 const std::array<std::optional<int2>, 2> neighbors = find_edge_neighbors(
1068 coarse_edges, vert_to_edge_map, coarse_edge_index);
1069 const std::array<float3, 4> points = find_loose_edge_interpolation_positions(
1070 coarse_positions, edge, neighbors);
1071 float4 weights;
1073 return bke::attribute_math::mix4(weights, points[0], points[1], points[2], points[3]);
1074}
1075
1077 const int2 &coarse_edge,
1078 const float u,
1079 const int subdiv_vertex_index)
1080{
1081 const Mesh *coarse_mesh = ctx->coarse_mesh;
1082 Mesh *subdiv_mesh = ctx->subdiv_mesh;
1083 /* This is never used for end-points (which are copied from the original). */
1084 BLI_assert(u > 0.0f);
1085 BLI_assert(u < 1.0f);
1086 const float interpolation_weights[2] = {1.0f - u, u};
1087 const int coarse_vertex_indices[2] = {coarse_edge[0], coarse_edge[1]};
1088 CustomData_interp(&coarse_mesh->vert_data,
1089 &subdiv_mesh->vert_data,
1090 coarse_vertex_indices,
1091 interpolation_weights,
1092 nullptr,
1093 2,
1094 subdiv_vertex_index);
1095 if (ctx->vert_origindex != nullptr) {
1096 ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE;
1097 }
1098}
1099
1100static void subdiv_mesh_vertex_of_loose_edge(const ForeachContext *foreach_context,
1101 void * /*tls*/,
1102 const int coarse_edge_index,
1103 const float u,
1104 const int subdiv_vertex_index)
1105{
1106 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
1107 const int2 &coarse_edge = ctx->coarse_edges[coarse_edge_index];
1108 const bool is_simple = ctx->subdiv->settings.is_simple;
1109
1110 /* Interpolate custom data when not an end point.
1111 * This data has already been copied from the original vertex by #subdiv_mesh_vertex_loose. */
1112 if (!ELEM(u, 0.0, 1.0)) {
1113 subdiv_mesh_vertex_of_loose_edge_interpolate(ctx, coarse_edge, u, subdiv_vertex_index);
1114 }
1115 /* Interpolate coordinate. */
1116 ctx->subdiv_positions[subdiv_vertex_index] = mesh_interpolate_position_on_edge(
1117 ctx->coarse_positions,
1118 ctx->coarse_edges,
1119 ctx->vert_to_edge_map,
1120 coarse_edge_index,
1121 is_simple,
1122 u);
1123}
1124
1127/* -------------------------------------------------------------------- */
1131static void setup_foreach_callbacks(const SubdivMeshContext *subdiv_context,
1132 ForeachContext *foreach_context)
1133{
1134 memset(foreach_context, 0, sizeof(*foreach_context));
1135 /* General information. */
1136 foreach_context->topology_info = subdiv_mesh_topology_info;
1137 /* Every boundary geometry. Used for displacement averaging. */
1138 if (subdiv_context->have_displacement) {
1141 }
1142 foreach_context->vertex_corner = subdiv_mesh_vertex_corner;
1143 foreach_context->vertex_edge = subdiv_mesh_vertex_edge;
1144 foreach_context->vertex_inner = subdiv_mesh_vertex_inner;
1145 foreach_context->edge = subdiv_mesh_edge;
1146 foreach_context->loop = subdiv_mesh_loop;
1147 foreach_context->poly = subdiv_mesh_face;
1148 foreach_context->vertex_loose = subdiv_mesh_vertex_loose;
1150 foreach_context->user_data_tls_free = subdiv_mesh_tls_free;
1151}
1152
1155/* -------------------------------------------------------------------- */
1159Mesh *subdiv_to_mesh(Subdiv *subdiv, const ToMeshSettings *settings, const Mesh *coarse_mesh)
1160{
1161
1163 /* Make sure evaluator is up to date with possible new topology, and that
1164 * it is refined for the new positions of coarse vertices. */
1165 if (!eval_begin_from_mesh(subdiv, coarse_mesh, {}, SUBDIV_EVALUATOR_TYPE_CPU, nullptr)) {
1166 /* This could happen in two situations:
1167 * - OpenSubdiv is disabled.
1168 * - Something totally bad happened, and OpenSubdiv rejected our
1169 * topology.
1170 * In either way, we can't safely continue. */
1171 if (coarse_mesh->faces_num) {
1173 return nullptr;
1174 }
1175 }
1176 /* Initialize subdivision mesh creation context. */
1177 SubdivMeshContext subdiv_context{};
1178 subdiv_context.settings = settings;
1179
1180 subdiv_context.coarse_mesh = coarse_mesh;
1181 subdiv_context.coarse_positions = coarse_mesh->vert_positions();
1182 subdiv_context.coarse_edges = coarse_mesh->edges();
1183 subdiv_context.coarse_faces = coarse_mesh->faces();
1184 subdiv_context.coarse_corner_verts = coarse_mesh->corner_verts();
1185 if (coarse_mesh->loose_edges().count > 0) {
1186 subdiv_context.vert_to_edge_map = mesh::build_vert_to_edge_map(
1187 subdiv_context.coarse_edges,
1188 coarse_mesh->verts_num,
1189 subdiv_context.vert_to_edge_offsets,
1190 subdiv_context.vert_to_edge_indices);
1191 }
1192
1193 subdiv_context.subdiv = subdiv;
1194 subdiv_context.have_displacement = (subdiv->displacement_evaluator != nullptr);
1195 /* Multi-threaded traversal/evaluation. */
1197 ForeachContext foreach_context;
1198 setup_foreach_callbacks(&subdiv_context, &foreach_context);
1199 SubdivMeshTLS tls{};
1200 foreach_context.user_data = &subdiv_context;
1201 foreach_context.user_data_tls_size = sizeof(SubdivMeshTLS);
1202 foreach_context.user_data_tls = &tls;
1203 foreach_subdiv_geometry(subdiv, &foreach_context, settings, coarse_mesh);
1205 Mesh *result = subdiv_context.subdiv_mesh;
1206
1207 CustomData_add_layer_named_with_data(&result->corner_data,
1209 subdiv_context.subdiv_corner_verts,
1210 result->corners_num,
1211 ".corner_vert",
1212 nullptr);
1213 subdiv_context.subdiv_corner_verts = nullptr;
1214 CustomData_add_layer_named_with_data(&result->corner_data,
1216 subdiv_context.subdiv_corner_edges,
1217 result->corners_num,
1218 ".corner_edge",
1219 nullptr);
1220 subdiv_context.subdiv_corner_edges = nullptr;
1221
1222 /* NOTE: Using normals from the limit surface gives different results than Blender's vertex
1223 * normal calculation. Since vertex normals are supposed to be a consistent cache, don't bother
1224 * calculating them here. The work may have been pointless anyway if the mesh is deformed or
1225 * changed afterwards. */
1226
1227 /* Move the optimal display edge array to the final bit vector. */
1228 if (!subdiv_context.subdiv_display_edges.is_empty()) {
1229 result->runtime->subsurf_optimal_display_edges = BitVector<>(
1230 subdiv_context.subdiv_display_edges);
1231 }
1232
1233 if (coarse_mesh->verts_no_face().count == 0) {
1234 result->tag_loose_verts_none();
1235 }
1236 if (coarse_mesh->loose_edges().count == 0) {
1237 result->tag_loose_edges_none();
1238 }
1239 result->tag_overlapping_none();
1240
1241 if (subdiv->settings.is_simple) {
1242 /* In simple subdivision, min and max positions are not changed, avoid recomputing bounds. */
1243 result->runtime->bounds_cache = coarse_mesh->runtime->bounds_cache;
1244 }
1245
1246 // BKE_mesh_validate(result, true, true);
1248 subdiv_mesh_context_free(&subdiv_context);
1249 return result;
1250}
1251
1254} // namespace blender::bke::subdiv
CustomData interface, see also DNA_customdata_types.h.
const CustomData_MeshMasks CD_MASK_EVERYTHING
bool CustomData_free_layer_named(CustomData *data, blender::StringRef name, const int totelem)
@ CD_SET_DEFAULT
void CustomData_interp(const CustomData *source, CustomData *dest, const int *src_indices, const float *weights, const float *sub_weights, int count, int dest_index)
void CustomData_init_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, int totelem)
void CustomData_free(CustomData *data, int totelem)
#define ORIGINDEX_NONE
void CustomData_init_layout_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, int totelem)
void * CustomData_get_layer_for_write(CustomData *data, eCustomDataType type, int totelem)
void CustomData_free_elem(CustomData *data, int index, int count)
void CustomData_copy_data(const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
const void * CustomData_add_layer_named_with_data(CustomData *data, eCustomDataType type, void *layer_data, int totelem, blender::StringRef name, const blender::ImplicitSharingInfo *sharing_info)
int CustomData_number_of_layers(const CustomData *data, eCustomDataType type)
void * CustomData_get_layer_n_for_write(CustomData *data, eCustomDataType type, int n, int totelem)
void key_curve_position_weights(float t, float data[4], int type)
Definition key.cc:339
void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
#define D
#define BLI_assert(a)
Definition BLI_assert.h:50
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
#define ELEM(...)
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
@ CD_CLOTH_ORCO
#define MAX_MTFACE
@ KEY_BSPLINE
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
ATTR_WARN_UNUSED_RESULT const BMVert * v
const T * data() const
Definition BLI_array.hh:301
constexpr int64_t size() const
constexpr int64_t start() const
constexpr int64_t size() const
Definition BLI_span.hh:253
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_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:43
T mix4(const float4 &weights, const T &v0, const T &v1, const T &v2, const T &v3)
int edge_other_vert(const int2 edge, const int vert)
Definition BKE_mesh.hh:307
GroupedSpan< int > build_vert_to_edge_map(Span< int2 > edges, int verts_num, Array< int > &r_offsets, Array< int > &r_indices)
void eval_vertex_data(Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_vertex_data[])
static void subdiv_mesh_ensure_loop_interpolation(SubdivMeshContext *ctx, SubdivMeshTLS *tls, const int coarse_face_index, const int coarse_corner)
static void subdiv_mesh_ensure_vertex_interpolation(SubdivMeshContext *ctx, SubdivMeshTLS *tls, const int coarse_face_index, const int coarse_corner)
static void vertex_interpolation_init(const SubdivMeshContext *ctx, VerticesForInterpolation *vertex_interpolation, const IndexRange coarse_face)
static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx)
static void loop_interpolation_from_corner(const SubdivMeshContext *ctx, LoopsForInterpolation *loop_interpolation, const IndexRange coarse_face, const int corner)
static void loop_interpolation_init(const SubdivMeshContext *ctx, LoopsForInterpolation *loop_interpolation, const IndexRange coarse_face)
static void subdiv_mesh_vertex_loose(const ForeachContext *foreach_context, void *, const int coarse_vertex_index, const int subdiv_vertex_index)
float3 mesh_interpolate_position_on_edge(Span< float3 > coarse_positions, Span< int2 > coarse_edges, GroupedSpan< int > vert_to_edge_map, int coarse_edge_index, bool is_simple, float u)
static void evaluate_vertex_and_apply_displacement_copy(const SubdivMeshContext *ctx, const int ptex_face_index, const float u, const float v, const int coarse_vertex_index, const int subdiv_vertex_index)
bool foreach_subdiv_geometry(Subdiv *subdiv, const ForeachContext *context, const ToMeshSettings *mesh_settings, const Mesh *coarse_mesh)
static void subdiv_mesh_vertex_displacement_every_corner(const ForeachContext *foreach_context, void *tls, const int ptex_face_index, const float u, const float v, const int, const int, const int, const int subdiv_vertex_index)
static void subdiv_vertex_data_copy(const SubdivMeshContext *ctx, const int coarse_vertex_index, const int subdiv_vertex_index)
static void subdiv_mesh_vertex_inner(const ForeachContext *foreach_context, void *tls_v, const int ptex_face_index, const float u, const float v, const int coarse_face_index, const int coarse_corner, const int subdiv_vertex_index)
static void subdiv_mesh_vertex_of_loose_edge_interpolate(SubdivMeshContext *ctx, const int2 &coarse_edge, const float u, const int subdiv_vertex_index)
static bool subdiv_mesh_is_center_vertex(const IndexRange coarse_face, const float u, const float v)
bool eval_begin_from_mesh(Subdiv *subdiv, const Mesh *mesh, Span< float3 > coarse_vert_positions, eSubdivEvaluatorType evaluator_type, OpenSubdiv_EvaluatorCache *evaluator_cache)
void eval_limit_point(Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3])
void eval_displacement(Subdiv *subdiv, int ptex_face_index, float u, float v, const float dPdu[3], const float dPdv[3], float r_D[3])
void eval_limit_point_and_derivatives(Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3], float r_dPdu[3], float r_dPdv[3])
void eval_face_varying(Subdiv *subdiv, int face_varying_channel, int ptex_face_index, float u, float v, float r_face_varying[2])
static void subdiv_mesh_edge(const ForeachContext *foreach_context, void *, const int coarse_edge_index, const int subdiv_edge_index, const bool, const int subdiv_v1, const int subdiv_v2)
static void subdiv_mesh_vertex_edge(const ForeachContext *foreach_context, void *tls_v, const int ptex_face_index, const float u, const float v, const int, const int coarse_face_index, const int coarse_corner, const int subdiv_vertex_index)
static void loops_of_ptex_get(LoopsOfPtex *loops_of_ptex, const IndexRange coarse_face, const int ptex_of_face_index)
static void vertex_interpolation_from_corner(const SubdivMeshContext *ctx, VerticesForInterpolation *vertex_interpolation, const IndexRange coarse_face, const int corner)
static void vertex_interpolation_end(VerticesForInterpolation *vertex_interpolation)
static void subdiv_mesh_tag_center_vertex(const IndexRange coarse_face, const int subdiv_vertex_index, const float u, const float v, Mesh *subdiv_mesh)
static void subdiv_eval_uv_layer(SubdivMeshContext *ctx, const int corner_index, const int ptex_face_index, const float u, const float v)
static void subdiv_mesh_vertex_displacement_every_edge(const ForeachContext *foreach_context, void *tls, const int ptex_face_index, const float u, const float v, const int, const int, const int, const int subdiv_vertex_index)
static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context, ForeachContext *foreach_context)
static void subdiv_mesh_prepare_accumulator(SubdivDeformContext *ctx, int num_vertices)
static void subdiv_mesh_vertex_displacement_every_corner_or_edge(const ForeachContext *foreach_context, void *, const int ptex_face_index, const float u, const float v, const int subdiv_vertex_index)
static std::array< std::optional< int2 >, 2 > find_edge_neighbors(const Span< int2 > coarse_edges, const GroupedSpan< int > vert_to_edge_map, const int edge_index)
static void subdiv_mesh_tls_free(void *tls_v)
void stats_begin(SubdivStats *stats, StatsValue value)
static void subdiv_mesh_vertex_of_loose_edge(const ForeachContext *foreach_context, void *, const int coarse_edge_index, const float u, const int subdiv_vertex_index)
void stats_end(SubdivStats *stats, StatsValue value)
static void subdiv_mesh_vertex_corner(const ForeachContext *foreach_context, void *, const int ptex_face_index, const float u, const float v, const int coarse_vertex_index, const int, const int, const int)
static void subdiv_mesh_loop(const ForeachContext *foreach_context, void *tls_v, const int ptex_face_index, const float u, const float v, const int, const int coarse_face_index, const int coarse_corner, const int subdiv_loop_index, const int subdiv_vertex_index, const int subdiv_edge_index)
Mesh * subdiv_to_mesh(Subdiv *subdiv, const ToMeshSettings *settings, const Mesh *coarse_mesh)
static void subdiv_accumulate_vertex_displacement(SubdivDeformContext *ctx, const int ptex_face_index, const float u, const float v, int vertex_index)
static std::array< float3, 4 > find_loose_edge_interpolation_positions(const Span< float3 > coarse_positions, const int2 &coarse_edge, const std::array< std::optional< int2 >, 2 > &neighbors)
static void subdiv_vertex_orco_evaluate(const SubdivMeshContext *ctx, const int ptex_face_index, const float u, const float v, const int subdiv_vertex_index)
static bool subdiv_mesh_topology_info(const ForeachContext *foreach_context, const int, const int, const int, const int, const int *)
static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation)
static void subdiv_mesh_ctx_cache_custom_data_layers(SubdivMeshContext *ctx)
static void subdiv_mesh_face(const ForeachContext *foreach_context, void *, const int coarse_face_index, const int subdiv_face_index, const int start_loop_index, const int)
static void subdiv_interpolate_corner_data(const SubdivMeshContext *ctx, const int subdiv_loop_index, const LoopsForInterpolation *loop_interpolation, const float u, const float v)
static void subdiv_mesh_context_free(SubdivDeformContext *ctx)
static void evaluate_vertex_and_apply_displacement_interpolate(const SubdivMeshContext *ctx, const int ptex_face_index, const float u, const float v, VerticesForInterpolation *vertex_interpolation, const int subdiv_vertex_index)
void eval_final_point(Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3])
static void subdiv_vertex_data_interpolate(const SubdivMeshContext *ctx, const int subdiv_vertex_index, const VerticesForInterpolation *vertex_interpolation, const float u, const float v)
static void subdiv_copy_edge_data(SubdivMeshContext *ctx, const int subdiv_edge_index, const int coarse_edge_index)
Mesh * mesh_new_no_attributes(int verts_num, int edges_num, int faces_num, int corners_num)
T interpolate(const T &a, const T &b, const FactorT &t)
int corners_num
CustomData edge_data
int edges_num
MeshRuntimeHandle * runtime
CustomData corner_data
CustomData face_data
CustomData vert_data
int faces_num
int verts_num
ForeachTopologyInformationCb topology_info
ForeachVertexOfLooseEdgeCb vertex_of_loose_edge
ForeachVertexFromCornerCb vertex_every_corner
LoopsForInterpolation loop_interpolation
VerticesForInterpolation vertex_interpolation
Displacement * displacement_evaluator