Blender V4.5
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_eval.hh"
24#include "BKE_subdiv_foreach.hh"
25#include "BKE_subdiv_mesh.hh"
26
27#include "MEM_guardedalloc.h"
28
29namespace blender::bke::subdiv {
30
31/* -------------------------------------------------------------------- */
34
42
49
55
62
63 /* Cached custom data arrays for faster access. */
68 /* UV layers interpolation. */
71
72 /* Original coordinates (ORCO) interpolation. */
73 float (*orco)[3];
74 float (*cloth_orco)[3];
75 /* Per-subdivided vertex counter of averaged values. */
78
79 /* Write optimal display edge tags into a boolean array rather than the final bit vector
80 * to avoid race conditions when setting bits. */
82
83 /* Lazily initialize a map from vertices to connected edges. */
87};
88
90{
91 Mesh *subdiv_mesh = ctx->subdiv_mesh;
92 ctx->num_uv_layers = std::min(
94 for (int layer_index = 0; layer_index < ctx->num_uv_layers; layer_index++) {
95 ctx->uv_layers[layer_index] = static_cast<float2 *>(CustomData_get_layer_n_for_write(
96 &subdiv_mesh->corner_data, CD_PROP_FLOAT2, layer_index, subdiv_mesh->corners_num));
97 }
98}
99
101{
102 Mesh *subdiv_mesh = ctx->subdiv_mesh;
103 ctx->subdiv_positions = subdiv_mesh->vert_positions_for_write();
104 ctx->subdiv_edges = subdiv_mesh->edges_for_write();
105 ctx->subdiv_face_offsets = subdiv_mesh->face_offsets_for_write();
106 /* Pointers to original indices layers. */
107 ctx->vert_origindex = static_cast<int *>(CustomData_get_layer_for_write(
108 &subdiv_mesh->vert_data, CD_ORIGINDEX, subdiv_mesh->verts_num));
109 ctx->edge_origindex = static_cast<int *>(CustomData_get_layer_for_write(
110 &subdiv_mesh->edge_data, CD_ORIGINDEX, subdiv_mesh->edges_num));
111 ctx->loop_origindex = static_cast<int *>(CustomData_get_layer_for_write(
112 &subdiv_mesh->corner_data, CD_ORIGINDEX, subdiv_mesh->corners_num));
113 ctx->face_origindex = static_cast<int *>(CustomData_get_layer_for_write(
114 &subdiv_mesh->face_data, CD_ORIGINDEX, subdiv_mesh->faces_num));
115 /* UV layers interpolation. */
117 /* Orco interpolation. */
118 ctx->orco = static_cast<float(*)[3]>(
119 CustomData_get_layer_for_write(&subdiv_mesh->vert_data, CD_ORCO, subdiv_mesh->verts_num));
120 ctx->cloth_orco = static_cast<float(*)[3]>(CustomData_get_layer_for_write(
121 &subdiv_mesh->vert_data, CD_CLOTH_ORCO, subdiv_mesh->verts_num));
122}
123
124static void subdiv_mesh_prepare_accumulator(SubdivMeshContext *ctx, int num_vertices)
125{
126 if (!ctx->have_displacement) {
127 return;
128 }
129 ctx->accumulated_counters = MEM_calloc_arrayN<int>(num_vertices, __func__);
130}
131
139
141
142/* -------------------------------------------------------------------- */
145
147 /* First loop of the ptex, starts at ptex (0, 0) and goes in u direction. */
149 /* Last loop of the ptex, starts at ptex (0, 0) and goes in v direction. */
151 /* For quad coarse faces only. */
154};
155
156static void loops_of_ptex_get(LoopsOfPtex *loops_of_ptex,
157 const IndexRange coarse_face,
158 const int ptex_of_face_index)
159{
160 const int first_ptex_loop_index = coarse_face.start() + ptex_of_face_index;
161 /* Loop which look in the (opposite) V direction of the current
162 * ptex face.
163 *
164 * TODO(sergey): Get rid of using module on every iteration. */
165 const int last_ptex_loop_index = coarse_face.start() +
166 (ptex_of_face_index + coarse_face.size() - 1) %
167 coarse_face.size();
168 loops_of_ptex->first_loop = first_ptex_loop_index;
169 loops_of_ptex->last_loop = last_ptex_loop_index;
170 if (coarse_face.size() == 4) {
171 loops_of_ptex->second_loop = loops_of_ptex->first_loop + 1;
172 loops_of_ptex->third_loop = loops_of_ptex->first_loop + 2;
173 }
174 else {
175 loops_of_ptex->second_loop = -1;
176 loops_of_ptex->third_loop = -1;
177 }
178}
179
181
182/* -------------------------------------------------------------------- */
185
186/* TODO(sergey): Somehow de-duplicate with loops storage, without too much
187 * exception cases all over the code. */
188
190 /* This field points to a vertex data which is to be used for interpolation.
191 * The idea is to avoid unnecessary allocations for regular faces, where
192 * we can simply use corner vertices. */
194 /* Vertices data calculated for ptex corners. There are always 4 elements
195 * in this custom data, aligned the following way:
196 *
197 * index 0 -> uv (0, 0)
198 * index 1 -> uv (0, 1)
199 * index 2 -> uv (1, 1)
200 * index 3 -> uv (1, 0)
201 *
202 * Is allocated for non-regular faces (triangles and n-gons). */
205 /* Indices within vertex_data to interpolate for. The indices are aligned
206 * with uv coordinates in a similar way as indices in corner_data_storage. */
208};
209
211 VerticesForInterpolation *vertex_interpolation,
212 const IndexRange coarse_face)
213{
214 const Mesh *coarse_mesh = ctx->coarse_mesh;
215 if (coarse_face.size() == 4) {
216 vertex_interpolation->vertex_data = &coarse_mesh->vert_data;
217 vertex_interpolation->vertex_indices[0] = ctx->coarse_corner_verts[coarse_face.start() + 0];
218 vertex_interpolation->vertex_indices[1] = ctx->coarse_corner_verts[coarse_face.start() + 1];
219 vertex_interpolation->vertex_indices[2] = ctx->coarse_corner_verts[coarse_face.start() + 2];
220 vertex_interpolation->vertex_indices[3] = ctx->coarse_corner_verts[coarse_face.start() + 3];
221 vertex_interpolation->vertex_data_storage_allocated = false;
222 }
223 else {
224 vertex_interpolation->vertex_data = &vertex_interpolation->vertex_data_storage;
225 /* Allocate storage for loops corresponding to ptex corners. */
227 &vertex_interpolation->vertex_data_storage,
228 CD_MASK_EVERYTHING.vmask,
230 4);
231 /* Initialize indices. */
232 vertex_interpolation->vertex_indices[0] = 0;
233 vertex_interpolation->vertex_indices[1] = 1;
234 vertex_interpolation->vertex_indices[2] = 2;
235 vertex_interpolation->vertex_indices[3] = 3;
236 vertex_interpolation->vertex_data_storage_allocated = true;
237 /* Interpolate center of face right away, it stays unchanged for all
238 * ptex faces. */
239 const float weight = 1.0f / float(coarse_face.size());
240 Array<float, 32> weights(coarse_face.size());
241 Array<int, 32> indices(coarse_face.size());
242 for (int i = 0; i < coarse_face.size(); i++) {
243 weights[i] = weight;
244 indices[i] = ctx->coarse_corner_verts[coarse_face.start() + i];
245 }
246 CustomData_interp(&coarse_mesh->vert_data,
247 &vertex_interpolation->vertex_data_storage,
248 indices.data(),
249 weights.data(),
250 nullptr,
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]};
289 CustomData_interp(vertex_data,
290 &vertex_interpolation->vertex_data_storage,
291 first_indices,
292 weights,
293 nullptr,
294 2,
295 1);
296 CustomData_interp(vertex_data,
297 &vertex_interpolation->vertex_data_storage,
298 last_indices,
299 weights,
300 nullptr,
301 2,
302 3);
303 }
304}
305
306static void vertex_interpolation_end(VerticesForInterpolation *vertex_interpolation)
307{
308 if (vertex_interpolation->vertex_data_storage_allocated) {
309 CustomData_free(&vertex_interpolation->vertex_data_storage);
310 }
311}
312
314
315/* -------------------------------------------------------------------- */
318
320 /* This field points to a loop data which is to be used for interpolation.
321 * The idea is to avoid unnecessary allocations for regular faces, where
322 * we can simply interpolate corner vertices. */
324 /* Loops data calculated for ptex corners. There are always 4 elements
325 * in this custom data, aligned the following way:
326 *
327 * index 0 -> uv (0, 0)
328 * index 1 -> uv (0, 1)
329 * index 2 -> uv (1, 1)
330 * index 3 -> uv (1, 0)
331 *
332 * Is allocated for non-regular faces (triangles and n-gons). */
335 /* Indices within corner_data to interpolate for. The indices are aligned with
336 * uv coordinates in a similar way as indices in corner_data_storage. */
338};
339
341 LoopsForInterpolation *loop_interpolation,
342 const IndexRange coarse_face)
343{
344 if (coarse_face.size() == 4) {
345 loop_interpolation->corner_data = &ctx->coarse_corner_data_interp;
346 loop_interpolation->loop_indices[0] = coarse_face.start() + 0;
347 loop_interpolation->loop_indices[1] = coarse_face.start() + 1;
348 loop_interpolation->loop_indices[2] = coarse_face.start() + 2;
349 loop_interpolation->loop_indices[3] = coarse_face.start() + 3;
350 loop_interpolation->corner_data_storage_allocated = false;
351 }
352 else {
353 loop_interpolation->corner_data = &loop_interpolation->corner_data_storage;
354 /* Allocate storage for loops corresponding to ptex corners. */
356 &loop_interpolation->corner_data_storage,
357 CD_MASK_EVERYTHING.lmask,
359 4);
360 /* Initialize indices. */
361 loop_interpolation->loop_indices[0] = 0;
362 loop_interpolation->loop_indices[1] = 1;
363 loop_interpolation->loop_indices[2] = 2;
364 loop_interpolation->loop_indices[3] = 3;
365 loop_interpolation->corner_data_storage_allocated = true;
366 /* Interpolate center of face right away, it stays unchanged for all
367 * ptex faces. */
368 const float weight = 1.0f / float(coarse_face.size());
369 Array<float, 32> weights(coarse_face.size());
370 Array<int, 32> indices(coarse_face.size());
371 for (int i = 0; i < coarse_face.size(); i++) {
372 weights[i] = weight;
373 indices[i] = coarse_face.start() + i;
374 }
376 &loop_interpolation->corner_data_storage,
377 indices.data(),
378 weights.data(),
379 nullptr,
380 coarse_face.size(),
381 2);
382 }
383}
384
386 LoopsForInterpolation *loop_interpolation,
387 const IndexRange coarse_face,
388 const int corner)
389{
390 if (coarse_face.size() == 4) {
391 /* Nothing to do, all indices and data is already assigned. */
392 }
393 else {
394 const CustomData *corner_data = &ctx->coarse_corner_data_interp;
395 LoopsOfPtex loops_of_ptex;
396 loops_of_ptex_get(&loops_of_ptex, coarse_face, corner);
397 /* PTEX face corner corresponds to a face loop with same index. */
398 CustomData_free_elem(&loop_interpolation->corner_data_storage, 0, 1);
400 corner_data, &loop_interpolation->corner_data_storage, coarse_face.start() + corner, 0, 1);
401 /* Interpolate remaining ptex face corners, which hits loops
402 * middle points.
403 *
404 * TODO(sergey): Re-use one of interpolation results from previous
405 * iteration. */
406 const float weights[2] = {0.5f, 0.5f};
407 const int base_loop_index = coarse_face.start();
408 const int first_loop_index = loops_of_ptex.first_loop;
409 const int second_loop_index = base_loop_index +
410 (first_loop_index - base_loop_index + 1) % coarse_face.size();
411 const int first_indices[2] = {first_loop_index, second_loop_index};
412 const int last_indices[2] = {loops_of_ptex.last_loop, loops_of_ptex.first_loop};
413 CustomData_interp(corner_data,
414 &loop_interpolation->corner_data_storage,
415 first_indices,
416 weights,
417 nullptr,
418 2,
419 1);
420 CustomData_interp(corner_data,
421 &loop_interpolation->corner_data_storage,
422 last_indices,
423 weights,
424 nullptr,
425 2,
426 3);
427 }
428}
429
430static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation)
431{
432 if (loop_interpolation->corner_data_storage_allocated) {
433 CustomData_free(&loop_interpolation->corner_data_storage);
434 }
435}
436
438
439/* -------------------------------------------------------------------- */
442
454
455static void subdiv_mesh_tls_free(void *tls_v)
456{
457 SubdivMeshTLS *tls = static_cast<SubdivMeshTLS *>(tls_v);
460 }
463 }
464}
465
467
468/* -------------------------------------------------------------------- */
471
473 const int ptex_face_index,
474 const float u,
475 const float v,
476 const int subdiv_vertex_index)
477{
478 if (ctx->orco || ctx->cloth_orco) {
479 float vertex_data[6];
480 eval_vertex_data(ctx->subdiv, ptex_face_index, u, v, vertex_data);
481
482 if (ctx->orco) {
483 copy_v3_v3(ctx->orco[subdiv_vertex_index], vertex_data);
484 if (ctx->cloth_orco) {
485 copy_v3_v3(ctx->cloth_orco[subdiv_vertex_index], vertex_data + 3);
486 }
487 }
488 else if (ctx->cloth_orco) {
489 copy_v3_v3(ctx->cloth_orco[subdiv_vertex_index], vertex_data);
490 }
491 }
492}
493
495
496/* -------------------------------------------------------------------- */
499
501 const int ptex_face_index,
502 const float u,
503 const float v,
504 const int subdiv_vertex_index)
505{
506 /* Accumulate displacement. */
507 Subdiv *subdiv = ctx->subdiv;
508 float dummy_P[3], dPdu[3], dPdv[3], D[3];
509 eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
510
511 /* NOTE: The subdivided mesh is allocated in this module, and its vertices are kept at zero
512 * locations as a default calloc(). */
513 eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
514 ctx->subdiv_positions[subdiv_vertex_index] += D;
515
516 if (ctx->accumulated_counters) {
517 ++ctx->accumulated_counters[subdiv_vertex_index];
518 }
519}
520
522
523/* -------------------------------------------------------------------- */
526
527static bool subdiv_mesh_topology_info(const ForeachContext *foreach_context,
528 const int num_vertices,
529 const int num_edges,
530 const int num_loops,
531 const int num_faces,
532 const int * /*subdiv_face_offset*/)
533{
534 /* Multi-resolution grid data will be applied or become invalid after subdivision,
535 * so don't try to preserve it and use memory. Crease values should also not be interpolated. */
538
539 SubdivMeshContext *subdiv_context = static_cast<SubdivMeshContext *>(foreach_context->user_data);
540
541 const Mesh &coarse_mesh = *subdiv_context->coarse_mesh;
543 num_vertices, num_edges, num_faces, num_loops);
544 Mesh &subdiv_mesh = *subdiv_context->subdiv_mesh;
545 BKE_mesh_copy_parameters_for_eval(subdiv_context->subdiv_mesh, &coarse_mesh);
546
547 CustomData_free(&subdiv_mesh.vert_data);
549 &coarse_mesh.vert_data, &subdiv_mesh.vert_data, mask.vmask, CD_SET_DEFAULT, num_vertices);
550 CustomData_free(&subdiv_mesh.edge_data);
552 &coarse_mesh.edge_data, &subdiv_mesh.edge_data, mask.emask, CD_SET_DEFAULT, num_edges);
553 CustomData_free(&subdiv_mesh.face_data);
555 &coarse_mesh.face_data, &subdiv_mesh.face_data, mask.pmask, CD_SET_DEFAULT, num_faces);
556 if (num_faces != 0) {
557 subdiv_mesh.face_offsets_for_write().last() = num_loops;
558 }
559
560 /* Create corner data for interpolation without topology attributes. */
562 &subdiv_context->coarse_corner_data_interp,
563 mask.lmask,
564 coarse_mesh.corners_num);
565 CustomData_free_layer_named(&subdiv_context->coarse_corner_data_interp, ".corner_vert");
566 CustomData_free_layer_named(&subdiv_context->coarse_corner_data_interp, ".corner_edge");
567 CustomData_free(&subdiv_mesh.corner_data);
569 &subdiv_mesh.corner_data,
570 mask.lmask,
572 num_loops);
573
574 /* Allocate corner topology arrays which are added to the result at the end. */
575 subdiv_context->subdiv_corner_verts = MEM_malloc_arrayN<int>(size_t(num_loops), __func__);
576 subdiv_context->subdiv_corner_edges = MEM_malloc_arrayN<int>(size_t(num_loops), __func__);
577
579 subdiv_mesh_prepare_accumulator(subdiv_context, num_vertices);
580 subdiv_mesh.runtime->subsurf_face_dot_tags.clear();
581 subdiv_mesh.runtime->subsurf_face_dot_tags.resize(num_vertices);
582 if (subdiv_context->settings->use_optimal_display) {
583 subdiv_context->subdiv_display_edges = Array<bool>(num_edges, false);
584 }
585 return true;
586}
587
589
590/* -------------------------------------------------------------------- */
593
595 const int coarse_vertex_index,
596 const int subdiv_vertex_index)
597{
598 const Mesh *coarse_mesh = ctx->coarse_mesh;
599 CustomData_copy_data(&coarse_mesh->vert_data,
600 &ctx->subdiv_mesh->vert_data,
601 coarse_vertex_index,
602 subdiv_vertex_index,
603 1);
604}
605
607 const int subdiv_vertex_index,
608 const VerticesForInterpolation *vertex_interpolation,
609 const float u,
610 const float v)
611{
612 const float weights[4] = {(1.0f - u) * (1.0f - v), u * (1.0f - v), u * v, (1.0f - u) * v};
613 CustomData_interp(vertex_interpolation->vertex_data,
614 &ctx->subdiv_mesh->vert_data,
615 vertex_interpolation->vertex_indices,
616 weights,
617 nullptr,
618 4,
619 subdiv_vertex_index);
620 if (ctx->vert_origindex != nullptr) {
621 ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE;
622 }
623}
624
626 const int ptex_face_index,
627 const float u,
628 const float v,
629 const int coarse_vertex_index,
630 const int subdiv_vertex_index)
631{
632 float3 &subdiv_position = ctx->subdiv_positions[subdiv_vertex_index];
633 /* Displacement is accumulated in subdiv vertex position.
634 * Needs to be backed up before copying data from original vertex. */
635 float D[3] = {0.0f, 0.0f, 0.0f};
636 if (ctx->have_displacement) {
637 const float inv_num_accumulated = 1.0f / ctx->accumulated_counters[subdiv_vertex_index];
638 copy_v3_v3(D, subdiv_position);
639 mul_v3_fl(D, inv_num_accumulated);
640 }
641 /* Copy custom data and evaluate position. */
642 subdiv_vertex_data_copy(ctx, coarse_vertex_index, subdiv_vertex_index);
643 eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_position);
644 /* Apply displacement. */
645 subdiv_position += D;
646 /* Evaluate undeformed texture coordinate. */
647 subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index);
648 /* Remove face-dot flag. This can happen if there is more than one subsurf modifier. */
649 ctx->subdiv_mesh->runtime->subsurf_face_dot_tags[subdiv_vertex_index].reset();
650}
651
653 const SubdivMeshContext *ctx,
654 const int ptex_face_index,
655 const float u,
656 const float v,
657 VerticesForInterpolation *vertex_interpolation,
658 const int subdiv_vertex_index)
659{
660 float3 &subdiv_position = ctx->subdiv_positions[subdiv_vertex_index];
661 /* Displacement is accumulated in subdiv vertex position.
662 * Needs to be backed up before copying data from original vertex. */
663 float D[3] = {0.0f, 0.0f, 0.0f};
664 if (ctx->have_displacement) {
665 const float inv_num_accumulated = 1.0f / ctx->accumulated_counters[subdiv_vertex_index];
666 copy_v3_v3(D, subdiv_position);
667 mul_v3_fl(D, inv_num_accumulated);
668 }
669 /* Interpolate custom data and evaluate position. */
670 subdiv_vertex_data_interpolate(ctx, subdiv_vertex_index, vertex_interpolation, u, v);
671 eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_position);
672 /* Apply displacement. */
673 add_v3_v3(subdiv_position, D);
674 /* Evaluate undeformed texture coordinate. */
675 subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index);
676}
677
679 const ForeachContext *foreach_context,
680 void * /*tls*/,
681 const int ptex_face_index,
682 const float u,
683 const float v,
684 const int subdiv_vertex_index)
685{
686 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
687 subdiv_accumulate_vertex_displacement(ctx, ptex_face_index, u, v, subdiv_vertex_index);
688}
689
691 void *tls,
692 const int ptex_face_index,
693 const float u,
694 const float v,
695 const int /*coarse_vertex_index*/,
696 const int /*coarse_face_index*/,
697 const int /*coarse_corner*/,
698 const int subdiv_vertex_index)
699{
701 foreach_context, tls, ptex_face_index, u, v, subdiv_vertex_index);
702}
703
705 void *tls,
706 const int ptex_face_index,
707 const float u,
708 const float v,
709 const int /*coarse_edge_index*/,
710 const int /*coarse_face_index*/,
711 const int /*coarse_corner*/,
712 const int subdiv_vertex_index)
713{
715 foreach_context, tls, ptex_face_index, u, v, subdiv_vertex_index);
716}
717
718static void subdiv_mesh_vertex_corner(const ForeachContext *foreach_context,
719 void * /*tls*/,
720 const int ptex_face_index,
721 const float u,
722 const float v,
723 const int coarse_vertex_index,
724 const int /*coarse_face_index*/,
725 const int /*coarse_corner*/,
726 const int subdiv_vertex_index)
727{
728 BLI_assert(coarse_vertex_index != ORIGINDEX_NONE);
729 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
731 ctx, ptex_face_index, u, v, coarse_vertex_index, subdiv_vertex_index);
732}
733
735 SubdivMeshTLS *tls,
736 const int coarse_face_index,
737 const int coarse_corner)
738{
739 const IndexRange coarse_face = ctx->coarse_faces[coarse_face_index];
740 /* Check whether we've moved to another corner or face. */
742 if (tls->vertex_interpolation_coarse_face_index != coarse_face_index ||
743 tls->vertex_interpolation_coarse_corner != coarse_corner)
744 {
747 }
748 }
749 /* Initialize the interpolation. */
751 vertex_interpolation_init(ctx, &tls->vertex_interpolation, coarse_face);
752 }
753 /* Update it for a new corner if needed. */
755 tls->vertex_interpolation_coarse_corner != coarse_corner)
756 {
757 vertex_interpolation_from_corner(ctx, &tls->vertex_interpolation, coarse_face, coarse_corner);
758 }
759 /* Store settings used for the current state of interpolator. */
761 tls->vertex_interpolation_coarse_face_index = coarse_face_index;
762 tls->vertex_interpolation_coarse_corner = coarse_corner;
763}
764
765static void subdiv_mesh_vertex_edge(const ForeachContext *foreach_context,
766 void *tls_v,
767 const int ptex_face_index,
768 const float u,
769 const float v,
770 const int /*coarse_edge_index*/,
771 const int coarse_face_index,
772 const int coarse_corner,
773 const int subdiv_vertex_index)
774{
775 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
776 SubdivMeshTLS *tls = static_cast<SubdivMeshTLS *>(tls_v);
777 subdiv_mesh_ensure_vertex_interpolation(ctx, tls, coarse_face_index, coarse_corner);
779 ctx, ptex_face_index, u, v, &tls->vertex_interpolation, subdiv_vertex_index);
780}
781
782static bool subdiv_mesh_is_center_vertex(const IndexRange coarse_face,
783 const float u,
784 const float v)
785{
786 if (coarse_face.size() == 4) {
787 if (u == 0.5f && v == 0.5f) {
788 return true;
789 }
790 }
791 else {
792 if (u == 1.0f && v == 1.0f) {
793 return true;
794 }
795 }
796 return false;
797}
798
799static void subdiv_mesh_tag_center_vertex(const IndexRange coarse_face,
800 const int subdiv_vertex_index,
801 const float u,
802 const float v,
803 Mesh *subdiv_mesh)
804{
805 if (subdiv_mesh_is_center_vertex(coarse_face, u, v)) {
806 subdiv_mesh->runtime->subsurf_face_dot_tags[subdiv_vertex_index].set();
807 }
808}
809
810static void subdiv_mesh_vertex_inner(const ForeachContext *foreach_context,
811 void *tls_v,
812 const int ptex_face_index,
813 const float u,
814 const float v,
815 const int coarse_face_index,
816 const int coarse_corner,
817 const int subdiv_vertex_index)
818{
819 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
820 SubdivMeshTLS *tls = static_cast<SubdivMeshTLS *>(tls_v);
821 Subdiv *subdiv = ctx->subdiv;
822 const IndexRange coarse_face = ctx->coarse_faces[coarse_face_index];
823 Mesh *subdiv_mesh = ctx->subdiv_mesh;
824 float3 &subdiv_position = ctx->subdiv_positions[subdiv_vertex_index];
825 subdiv_mesh_ensure_vertex_interpolation(ctx, tls, coarse_face_index, coarse_corner);
826 subdiv_vertex_data_interpolate(ctx, subdiv_vertex_index, &tls->vertex_interpolation, u, v);
827 eval_final_point(subdiv, ptex_face_index, u, v, subdiv_position);
828 subdiv_mesh_tag_center_vertex(coarse_face, subdiv_vertex_index, u, v, subdiv_mesh);
829 subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index);
830}
831
833
834/* -------------------------------------------------------------------- */
837
839 const int subdiv_edge_index,
840 const int coarse_edge_index)
841{
842 if (coarse_edge_index == ORIGINDEX_NONE) {
843 if (ctx->edge_origindex != nullptr) {
844 ctx->edge_origindex[subdiv_edge_index] = ORIGINDEX_NONE;
845 }
846 return;
847 }
849 &ctx->subdiv_mesh->edge_data,
850 coarse_edge_index,
851 subdiv_edge_index,
852 1);
853 if (ctx->settings->use_optimal_display) {
854 ctx->subdiv_display_edges[subdiv_edge_index] = true;
855 }
856}
857
858static void subdiv_mesh_edge(const ForeachContext *foreach_context,
859 void * /*tls*/,
860 const int coarse_edge_index,
861 const int subdiv_edge_index,
862 const bool /*is_loose*/,
863 const int subdiv_v1,
864 const int subdiv_v2)
865{
866 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
867 subdiv_copy_edge_data(ctx, subdiv_edge_index, coarse_edge_index);
868 ctx->subdiv_edges[subdiv_edge_index][0] = subdiv_v1;
869 ctx->subdiv_edges[subdiv_edge_index][1] = subdiv_v2;
870}
871
873
874/* -------------------------------------------------------------------- */
877
879 const int subdiv_loop_index,
880 const LoopsForInterpolation *loop_interpolation,
881 const float u,
882 const float v)
883{
884 const float weights[4] = {(1.0f - u) * (1.0f - v), u * (1.0f - v), u * v, (1.0f - u) * v};
885 CustomData_interp(loop_interpolation->corner_data,
887 loop_interpolation->loop_indices,
888 weights,
889 nullptr,
890 4,
891 subdiv_loop_index);
892 /* TODO(sergey): Set ORIGINDEX. */
893}
894
896 const int corner_index,
897 const int ptex_face_index,
898 const float u,
899 const float v)
900{
901 if (ctx->num_uv_layers == 0) {
902 return;
903 }
904 Subdiv *subdiv = ctx->subdiv;
905 for (int layer_index = 0; layer_index < ctx->num_uv_layers; layer_index++) {
907 subdiv, layer_index, ptex_face_index, u, v, ctx->uv_layers[layer_index][corner_index]);
908 }
909}
910
912 SubdivMeshTLS *tls,
913 const int coarse_face_index,
914 const int coarse_corner)
915{
916 const IndexRange coarse_face = ctx->coarse_faces[coarse_face_index];
917 /* Check whether we've moved to another corner or face. */
919 if (tls->loop_interpolation_coarse_face_index != coarse_face_index ||
920 tls->loop_interpolation_coarse_corner != coarse_corner)
921 {
924 }
925 }
926 /* Initialize the interpolation. */
928 loop_interpolation_init(ctx, &tls->loop_interpolation, coarse_face);
929 }
930 /* Update it for a new corner if needed. */
932 tls->loop_interpolation_coarse_corner != coarse_corner)
933 {
934 loop_interpolation_from_corner(ctx, &tls->loop_interpolation, coarse_face, coarse_corner);
935 }
936 /* Store settings used for the current state of interpolator. */
938 tls->loop_interpolation_coarse_face_index = coarse_face_index;
939 tls->loop_interpolation_coarse_corner = coarse_corner;
940}
941
942static void subdiv_mesh_loop(const ForeachContext *foreach_context,
943 void *tls_v,
944 const int ptex_face_index,
945 const float u,
946 const float v,
947 const int /*coarse_loop_index*/,
948 const int coarse_face_index,
949 const int coarse_corner,
950 const int subdiv_loop_index,
951 const int subdiv_vertex_index,
952 const int subdiv_edge_index)
953{
954 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
955 SubdivMeshTLS *tls = static_cast<SubdivMeshTLS *>(tls_v);
956 subdiv_mesh_ensure_loop_interpolation(ctx, tls, coarse_face_index, coarse_corner);
957 subdiv_interpolate_corner_data(ctx, subdiv_loop_index, &tls->loop_interpolation, u, v);
958 subdiv_eval_uv_layer(ctx, subdiv_loop_index, ptex_face_index, u, v);
959 ctx->subdiv_corner_verts[subdiv_loop_index] = subdiv_vertex_index;
960 ctx->subdiv_corner_edges[subdiv_loop_index] = subdiv_edge_index;
961}
962
964
965/* -------------------------------------------------------------------- */
968
969static void subdiv_mesh_face(const ForeachContext *foreach_context,
970 void * /*tls*/,
971 const int coarse_face_index,
972 const int subdiv_face_index,
973 const int start_loop_index,
974 const int /*num_loops*/)
975{
976 BLI_assert(coarse_face_index != ORIGINDEX_NONE);
977 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
979 &ctx->subdiv_mesh->face_data,
980 coarse_face_index,
981 subdiv_face_index,
982 1);
983 ctx->subdiv_face_offsets[subdiv_face_index] = start_loop_index;
984}
985
987
988/* -------------------------------------------------------------------- */
991
992static void subdiv_mesh_vertex_loose(const ForeachContext *foreach_context,
993 void * /*tls*/,
994 const int coarse_vertex_index,
995 const int subdiv_vertex_index)
996{
997 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
998 subdiv_vertex_data_copy(ctx, coarse_vertex_index, subdiv_vertex_index);
999}
1000
1001/* Get neighbor edges of the given one.
1002 * - neighbors[0] is an edge adjacent to edge->v1.
1003 * - neighbors[1] is an edge adjacent to edge->v2. */
1004static std::array<std::optional<int2>, 2> find_edge_neighbors(
1005 const Span<int2> coarse_edges, const GroupedSpan<int> vert_to_edge_map, const int edge_index)
1006{
1007 /* Vertices which has more than one neighbor are considered infinitely
1008 * sharp. This is also how topology factory treats vertices of a surface
1009 * which are adjacent to a loose edge. */
1010 const auto neighbor_edge_if_single = [&](const int vert) -> std::optional<int2> {
1011 const Span<int> neighbors = vert_to_edge_map[vert];
1012 if (neighbors.size() != 2) {
1013 return std::nullopt;
1014 }
1015 return neighbors[0] == edge_index ? coarse_edges[neighbors[1]] : coarse_edges[neighbors[0]];
1016 };
1017 const int2 edge = coarse_edges[edge_index];
1018 return {neighbor_edge_if_single(edge[0]), neighbor_edge_if_single(edge[1])};
1019}
1020
1021static std::array<float3, 4> find_loose_edge_interpolation_positions(
1022 const Span<float3> coarse_positions,
1023 const int2 &coarse_edge,
1024 const std::array<std::optional<int2>, 2> &neighbors)
1025{
1026 std::array<float3, 4> result;
1027 /* Middle points corresponds to the edge. */
1028 result[1] = coarse_positions[coarse_edge[0]];
1029 result[2] = coarse_positions[coarse_edge[1]];
1030 /* Start point, duplicate from edge start if no neighbor. */
1031 if (const std::optional<int2> &other = neighbors[0]) {
1032 result[0] = coarse_positions[mesh::edge_other_vert(*other, coarse_edge[0])];
1033 }
1034 else {
1035 result[0] = result[1] * 2.0f - result[2];
1036 }
1037 /* End point, duplicate from edge end if no neighbor. */
1038 if (const std::optional<int2> &other = neighbors[1]) {
1039 result[3] = coarse_positions[mesh::edge_other_vert(*other, coarse_edge[1])];
1040 }
1041 else {
1042 result[3] = result[2] * 2.0f - result[1];
1043 }
1044 return result;
1045}
1046
1048 const Span<int2> coarse_edges,
1049 const GroupedSpan<int> vert_to_edge_map,
1050 const int coarse_edge_index,
1051 const bool is_simple,
1052 const float u)
1053{
1054 const int2 edge = coarse_edges[coarse_edge_index];
1055 if (is_simple) {
1056 return math::interpolate(coarse_positions[edge[0]], coarse_positions[edge[1]], u);
1057 }
1058 /* Find neighbors of the coarse edge. */
1059 const std::array<std::optional<int2>, 2> neighbors = find_edge_neighbors(
1060 coarse_edges, vert_to_edge_map, coarse_edge_index);
1061 const std::array<float3, 4> points = find_loose_edge_interpolation_positions(
1062 coarse_positions, edge, neighbors);
1063 float4 weights;
1065 return bke::attribute_math::mix4(weights, points[0], points[1], points[2], points[3]);
1066}
1067
1069 const int2 &coarse_edge,
1070 const float u,
1071 const int subdiv_vertex_index)
1072{
1073 const Mesh *coarse_mesh = ctx->coarse_mesh;
1074 Mesh *subdiv_mesh = ctx->subdiv_mesh;
1075 /* This is never used for end-points (which are copied from the original). */
1076 BLI_assert(u > 0.0f);
1077 BLI_assert(u < 1.0f);
1078 const float interpolation_weights[2] = {1.0f - u, u};
1079 const int coarse_vertex_indices[2] = {coarse_edge[0], coarse_edge[1]};
1080 CustomData_interp(&coarse_mesh->vert_data,
1081 &subdiv_mesh->vert_data,
1082 coarse_vertex_indices,
1083 interpolation_weights,
1084 nullptr,
1085 2,
1086 subdiv_vertex_index);
1087 if (ctx->vert_origindex != nullptr) {
1088 ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE;
1089 }
1090}
1091
1092static void subdiv_mesh_vertex_of_loose_edge(const ForeachContext *foreach_context,
1093 void * /*tls*/,
1094 const int coarse_edge_index,
1095 const float u,
1096 const int subdiv_vertex_index)
1097{
1098 SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data);
1099 const int2 &coarse_edge = ctx->coarse_edges[coarse_edge_index];
1100 const bool is_simple = ctx->subdiv->settings.is_simple;
1101
1102 /* Interpolate custom data when not an end point.
1103 * This data has already been copied from the original vertex by #subdiv_mesh_vertex_loose. */
1104 if (!ELEM(u, 0.0, 1.0)) {
1105 subdiv_mesh_vertex_of_loose_edge_interpolate(ctx, coarse_edge, u, subdiv_vertex_index);
1106 }
1107 /* Interpolate coordinate. */
1108 ctx->subdiv_positions[subdiv_vertex_index] = mesh_interpolate_position_on_edge(
1109 ctx->coarse_positions,
1110 ctx->coarse_edges,
1111 ctx->vert_to_edge_map,
1112 coarse_edge_index,
1113 is_simple,
1114 u);
1115}
1116
1118
1119/* -------------------------------------------------------------------- */
1122
1123static void setup_foreach_callbacks(const SubdivMeshContext *subdiv_context,
1124 ForeachContext *foreach_context)
1125{
1126 memset(foreach_context, 0, sizeof(*foreach_context));
1127 /* General information. */
1128 foreach_context->topology_info = subdiv_mesh_topology_info;
1129 /* Every boundary geometry. Used for displacement averaging. */
1130 if (subdiv_context->have_displacement) {
1133 }
1134 foreach_context->vertex_corner = subdiv_mesh_vertex_corner;
1135 foreach_context->vertex_edge = subdiv_mesh_vertex_edge;
1136 foreach_context->vertex_inner = subdiv_mesh_vertex_inner;
1137 foreach_context->edge = subdiv_mesh_edge;
1138 foreach_context->loop = subdiv_mesh_loop;
1139 foreach_context->poly = subdiv_mesh_face;
1140 foreach_context->vertex_loose = subdiv_mesh_vertex_loose;
1142 foreach_context->user_data_tls_free = subdiv_mesh_tls_free;
1143}
1144
1146
1147/* -------------------------------------------------------------------- */
1150
1151Mesh *subdiv_to_mesh(Subdiv *subdiv, const ToMeshSettings *settings, const Mesh *coarse_mesh)
1152{
1153
1155 /* Make sure evaluator is up to date with possible new topology, and that
1156 * it is refined for the new positions of coarse vertices. */
1157 if (!eval_begin_from_mesh(subdiv, coarse_mesh, {}, SUBDIV_EVALUATOR_TYPE_CPU, nullptr)) {
1158 /* This could happen in two situations:
1159 * - OpenSubdiv is disabled.
1160 * - Something totally bad happened, and OpenSubdiv rejected our
1161 * topology.
1162 * In either way, we can't safely continue. */
1163 if (coarse_mesh->faces_num) {
1165 return nullptr;
1166 }
1167 }
1168 /* Initialize subdivision mesh creation context. */
1169 SubdivMeshContext subdiv_context{};
1170 subdiv_context.settings = settings;
1171
1172 subdiv_context.coarse_mesh = coarse_mesh;
1173 subdiv_context.coarse_positions = coarse_mesh->vert_positions();
1174 subdiv_context.coarse_edges = coarse_mesh->edges();
1175 subdiv_context.coarse_faces = coarse_mesh->faces();
1176 subdiv_context.coarse_corner_verts = coarse_mesh->corner_verts();
1177 if (coarse_mesh->loose_edges().count > 0) {
1179 subdiv_context.coarse_edges,
1180 coarse_mesh->verts_num,
1181 subdiv_context.vert_to_edge_offsets,
1182 subdiv_context.vert_to_edge_indices);
1183 }
1184
1185 subdiv_context.subdiv = subdiv;
1186 subdiv_context.have_displacement = (subdiv->displacement_evaluator != nullptr);
1187 /* Multi-threaded traversal/evaluation. */
1189 ForeachContext foreach_context;
1190 setup_foreach_callbacks(&subdiv_context, &foreach_context);
1191 SubdivMeshTLS tls{};
1192 foreach_context.user_data = &subdiv_context;
1193 foreach_context.user_data_tls_size = sizeof(SubdivMeshTLS);
1194 foreach_context.user_data_tls = &tls;
1195 foreach_subdiv_geometry(subdiv, &foreach_context, settings, coarse_mesh);
1197 Mesh *result = subdiv_context.subdiv_mesh;
1198
1201 subdiv_context.subdiv_corner_verts,
1202 result->corners_num,
1203 ".corner_vert",
1204 nullptr);
1205 subdiv_context.subdiv_corner_verts = nullptr;
1208 subdiv_context.subdiv_corner_edges,
1209 result->corners_num,
1210 ".corner_edge",
1211 nullptr);
1212 subdiv_context.subdiv_corner_edges = nullptr;
1213
1214 /* NOTE: Using normals from the limit surface gives different results than Blender's vertex
1215 * normal calculation. Since vertex normals are supposed to be a consistent cache, don't bother
1216 * calculating them here. The work may have been pointless anyway if the mesh is deformed or
1217 * changed afterwards. */
1218
1219 /* Move the optimal display edge array to the final bit vector. */
1220 if (!subdiv_context.subdiv_display_edges.is_empty()) {
1221 result->runtime->subsurf_optimal_display_edges = BitVector<>(
1222 subdiv_context.subdiv_display_edges);
1223 }
1224
1225 if (coarse_mesh->verts_no_face().count == 0) {
1226 result->tag_loose_verts_none();
1227 }
1228 if (coarse_mesh->loose_edges().count == 0) {
1229 result->tag_loose_edges_none();
1230 }
1231 result->tag_overlapping_none();
1232
1233 if (subdiv->settings.is_simple) {
1234 /* In simple subdivision, min and max positions are not changed, avoid recomputing bounds. */
1235 result->runtime->bounds_cache = coarse_mesh->runtime->bounds_cache;
1236 }
1237
1238 // BKE_mesh_validate(result, true, true);
1240 subdiv_mesh_context_free(&subdiv_context);
1241 return result;
1242}
1243
1245
1246} // namespace blender::bke::subdiv
CustomData interface, see also DNA_customdata_types.h.
const CustomData_MeshMasks CD_MASK_EVERYTHING
@ 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_free(CustomData *data)
void CustomData_init_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, 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)
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:341
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
@ KEY_BSPLINE
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v
bool is_empty() const
Definition BLI_array.hh:253
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:252
static ushort indices[]
#define MEM_SAFE_FREE(v)
#define CD_MASK_MULTIRES_GRIDS
#define MAX_MTFACE
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:354
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)
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
LoopsForInterpolation loop_interpolation
VerticesForInterpolation vertex_interpolation
i
Definition text_draw.cc:230