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