Blender V4.5
multires_reshape_smooth.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "multires_reshape.hh"
10
11#include "MEM_guardedalloc.h"
12
13#include "DNA_mesh_types.h"
14
15#include "BLI_function_ref.hh"
16#include "BLI_math_matrix.h"
17#include "BLI_math_vector.h"
18#include "BLI_task.hh"
19#include "BLI_utildefines.h"
20
21#include "BKE_customdata.hh"
22#include "BKE_mesh.hh"
23#include "BKE_multires.hh"
24#include "BKE_subdiv.hh"
25#include "BKE_subdiv_eval.hh"
26#include "BKE_subdiv_foreach.hh"
27#include "BKE_subdiv_mesh.hh"
28
30#ifdef WITH_OPENSUBDIV
32#endif
34
35#include "atomic_ops.h"
36#include "subdiv_converter.hh"
37
38#ifdef WITH_OPENSUBDIV
39
40/* -------------------------------------------------------------------- */
43
44/* Surface refers to a simplified and lower-memory footprint representation of the limit surface.
45 *
46 * Used to store pre-calculated information which is expensive or impossible to evaluate when
47 * traversing the final limit surface. */
48
49struct SurfacePoint {
50 float P[3];
51 float tangent_matrix[3][3];
52};
53
54struct SurfaceGrid {
55 SurfacePoint *points;
56};
57
58/* Geometry elements which are used to simplify creation of topology refiner at the sculpt level.
59 * Contains a limited subset of information needed to construct topology refiner. */
60
61struct Vertex {
62 /* All grid coordinates which the vertex corresponding to.
63 * For a vertices which are created from inner points of grids there is always one coordinate. */
64 int num_grid_coords;
65 GridCoord *grid_coords;
66
67 float sharpness;
68 bool is_infinite_sharp;
69};
70
71struct Corner {
72 const Vertex *vertex;
73 int grid_index;
74};
75
76struct Edge {
77 int v1;
78 int v2;
79
80 float sharpness;
81};
82
83/* Storage of data which is linearly interpolated from the reshape level to the top level. */
84
85struct LinearGridElement {
86 float mask;
87};
88
89struct LinearGrid {
90 LinearGridElement *elements;
91};
92
93struct LinearGrids {
94 int num_grids;
95 int level;
96
97 /* Cached size for the grid, for faster lookup. */
98 int grid_size;
99
100 /* Indexed by grid index. */
101 LinearGrid *grids;
102
103 /* Elements for all grids are allocated in a single array, for the allocation performance. */
104 LinearGridElement *elements_storage;
105};
106
107/* Context which holds all information needed during propagation and smoothing. */
108
109struct MultiresReshapeSmoothContext {
110 const MultiresReshapeContext *reshape_context;
111
112 /* Geometry at a reshape multires level. */
113 struct {
114 int num_vertices;
115 Vertex *vertices;
116
117 /* Maximum number of edges which might be stored in the edges array.
118 * Is calculated based on the number of edges in the base mesh and the subdivision level. */
119 int max_edges;
120
121 /* Sparse storage of edges. Will only include edges which have non-zero sharpness.
122 *
123 * NOTE: Different type from others to be able to easier use atomic ops. */
124 size_t num_edges;
125 Edge *edges;
126
127 int num_corners;
129
130 int num_faces;
131 /* Face topology of subdivision level. */
132 blender::Array<int> face_offsets;
133
134 blender::OffsetIndices<int> faces() const
135 {
136 return blender::OffsetIndices<int>(face_offsets, blender::offset_indices::NoSortCheck());
137 }
138 } geometry;
139
140 /* Grids of data which is linearly interpolated between grid elements at the reshape level.
141 * The data is actually stored as a delta, which is then to be added to the higher levels. */
142 LinearGrids linear_delta_grids;
143
144 /* From #Mesh::loose_edges(). May be empty. */
145 blender::BitSpan loose_base_edges;
146
147 /* Subdivision surface created for geometry at a reshape level. */
148 blender::bke::subdiv::Subdiv *reshape_subdiv;
149
150 /* Limit surface of the base mesh with original sculpt level details on it, subdivided up to the
151 * top level.
152 * Is used as a base point to calculate how much displacement has been made in the sculpt mode.
153 *
154 * NOTE: Referring to sculpt as it is the main user of this functionality and it is clear to
155 * understand what it actually means in a concrete example. This is a generic code which is also
156 * used by Subdivide operation, but the idea is exactly the same as propagation in the sculpt
157 * mode. */
158 SurfaceGrid *base_surface_grids;
159
160 /* Defines how displacement is interpolated on the higher levels (for example, whether
161 * displacement is smoothed in Catmull-Clark mode or interpolated linearly preserving sharp edges
162 * of the current sculpt level).
163 *
164 * NOTE: Uses same enumerator type as Subdivide operator, since the values are the same and
165 * decoupling type just adds extra headache to convert one enumerator to another. */
166 MultiresSubdivideModeType smoothing_type;
167};
168
170
171/* -------------------------------------------------------------------- */
174
175static void linear_grids_init(LinearGrids *linear_grids)
176{
177 linear_grids->num_grids = 0;
178 linear_grids->level = 0;
179
180 linear_grids->grids = nullptr;
181 linear_grids->elements_storage = nullptr;
182}
183
184static void linear_grids_allocate(LinearGrids *linear_grids, int num_grids, int level)
185{
186 const size_t grid_size = blender::bke::subdiv::grid_size_from_level(level);
187 const size_t grid_area = grid_size * grid_size;
188 const size_t num_grid_elements = num_grids * grid_area;
189
190 linear_grids->num_grids = num_grids;
191 linear_grids->level = level;
192 linear_grids->grid_size = grid_size;
193
194 linear_grids->grids = MEM_malloc_arrayN<LinearGrid>(size_t(num_grids), __func__);
195 linear_grids->elements_storage = MEM_calloc_arrayN<LinearGridElement>(num_grid_elements,
196 __func__);
197
198 for (int i = 0; i < num_grids; ++i) {
199 const size_t element_offset = grid_area * i;
200 linear_grids->grids[i].elements = &linear_grids->elements_storage[element_offset];
201 }
202}
203
204static LinearGridElement *linear_grid_element_get(const LinearGrids *linear_grids,
205 const GridCoord *grid_coord)
206{
207 BLI_assert(grid_coord->grid_index >= 0);
208 BLI_assert(grid_coord->grid_index < linear_grids->num_grids);
209
210 const int grid_size = linear_grids->grid_size;
211
212 const int grid_x = lround(grid_coord->u * (grid_size - 1));
213 const int grid_y = lround(grid_coord->v * (grid_size - 1));
214 const int grid_element_index = grid_y * grid_size + grid_x;
215
216 LinearGrid *grid = &linear_grids->grids[grid_coord->grid_index];
217 return &grid->elements[grid_element_index];
218}
219
220static void linear_grids_free(LinearGrids *linear_grids)
221{
222 MEM_SAFE_FREE(linear_grids->grids);
223 MEM_SAFE_FREE(linear_grids->elements_storage);
224}
225
226static void linear_grid_element_init(LinearGridElement *linear_grid_element)
227{
228 linear_grid_element->mask = 0.0f;
229}
230
231/* result = a - b. */
232static void linear_grid_element_sub(LinearGridElement *result,
233 const LinearGridElement *a,
234 const LinearGridElement *b)
235{
236 result->mask = a->mask - b->mask;
237}
238
239static void linear_grid_element_interpolate(LinearGridElement *result,
240 const LinearGridElement elements[4],
241 const float weights[4])
242{
243 result->mask = elements[0].mask * weights[0] + elements[1].mask * weights[1] +
244 elements[2].mask * weights[2] + elements[3].mask * weights[3];
245}
246
248
249/* -------------------------------------------------------------------- */
252
253static void base_surface_grids_allocate(MultiresReshapeSmoothContext *reshape_smooth_context)
254{
255 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
256
257 const int num_grids = reshape_context->num_grids;
258 const int grid_size = reshape_context->top.grid_size;
259 const int grid_area = grid_size * grid_size;
260
261 SurfaceGrid *surface_grid = MEM_malloc_arrayN<SurfaceGrid>(size_t(num_grids), __func__);
262
263 for (int grid_index = 0; grid_index < num_grids; ++grid_index) {
264 surface_grid[grid_index].points = MEM_calloc_arrayN<SurfacePoint>(grid_area, __func__);
265 }
266
267 reshape_smooth_context->base_surface_grids = surface_grid;
268}
269
270static void base_surface_grids_free(MultiresReshapeSmoothContext *reshape_smooth_context)
271{
272 if (reshape_smooth_context->base_surface_grids == nullptr) {
273 return;
274 }
275
276 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
277
278 const int num_grids = reshape_context->num_grids;
279 for (int grid_index = 0; grid_index < num_grids; ++grid_index) {
280 MEM_freeN(reshape_smooth_context->base_surface_grids[grid_index].points);
281 }
282 MEM_freeN(reshape_smooth_context->base_surface_grids);
283}
284
285static SurfacePoint *base_surface_grids_read(
286 const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord)
287{
288 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
289
290 const int grid_index = grid_coord->grid_index;
291 const int grid_size = reshape_context->top.grid_size;
292 const int grid_x = lround(grid_coord->u * (grid_size - 1));
293 const int grid_y = lround(grid_coord->v * (grid_size - 1));
294 const int grid_element_index = grid_y * grid_size + grid_x;
295
296 SurfaceGrid *surface_grid = &reshape_smooth_context->base_surface_grids[grid_index];
297 return &surface_grid->points[grid_element_index];
298}
299
300static void base_surface_grids_write(const MultiresReshapeSmoothContext *reshape_smooth_context,
301 const GridCoord *grid_coord,
302 float P[3],
303 float tangent_matrix[3][3])
304{
305 SurfacePoint *point = base_surface_grids_read(reshape_smooth_context, grid_coord);
306 copy_v3_v3(point->P, P);
307 copy_m3_m3(point->tangent_matrix, tangent_matrix);
308}
309
311
312/* -------------------------------------------------------------------- */
315
316/* Find grid index which given face was created for. */
317static int get_face_grid_index(const MultiresReshapeSmoothContext *reshape_smooth_context,
318 const blender::IndexRange face)
319{
320 const Corner *first_corner = &reshape_smooth_context->geometry.corners[face.start()];
321 const int grid_index = first_corner->grid_index;
322
323# ifndef NDEBUG
324 for (const int corner_index : face) {
325 const Corner *corner = &reshape_smooth_context->geometry.corners[corner_index];
326 BLI_assert(corner->grid_index == grid_index);
327 }
328# endif
329
330 return grid_index;
331}
332
333static GridCoord *vertex_grid_coord_with_grid_index(const Vertex *vertex, const int grid_index)
334{
335 for (int i = 0; i < vertex->num_grid_coords; ++i) {
336 if (vertex->grid_coords[i].grid_index == grid_index) {
337 return &vertex->grid_coords[i];
338 }
339 }
340 return nullptr;
341}
342
343/* Get grid coordinates which correspond to corners of the given face.
344 * All the grid coordinates will be from the same grid index. */
345static void grid_coords_from_face_verts(const MultiresReshapeSmoothContext *reshape_smooth_context,
346 const blender::IndexRange face,
347 const GridCoord *grid_coords[])
348{
349 BLI_assert(face.size() == 4);
350
351 const int grid_index = get_face_grid_index(reshape_smooth_context, face);
352 BLI_assert(grid_index != -1);
353
354 for (const int i : face.index_range()) {
355 const int corner_index = face[i];
356 const Corner *corner = &reshape_smooth_context->geometry.corners[corner_index];
357 grid_coords[i] = vertex_grid_coord_with_grid_index(corner->vertex, grid_index);
358 BLI_assert(grid_coords[i] != nullptr);
359 }
360}
361
366static float lerp_f(float t, float a, float b)
367{
368 return (a + t * (b - a));
369}
370
371static void interpolate_grid_coord(GridCoord *result,
372 const GridCoord *face_grid_coords[4],
373 const float u,
374 const float v)
375{
376 /*
377 * v
378 * ^
379 * | (3) -------- (2)
380 * | | |
381 * | | |
382 * | | |
383 * | | |
384 * | (0) -------- (1)
385 * *--------------------------> u
386 */
387
388 const float u01 = lerp_f(u, face_grid_coords[0]->u, face_grid_coords[1]->u);
389 const float u32 = lerp_f(u, face_grid_coords[3]->u, face_grid_coords[2]->u);
390
391 const float v03 = lerp_f(v, face_grid_coords[0]->v, face_grid_coords[3]->v);
392 const float v12 = lerp_f(v, face_grid_coords[1]->v, face_grid_coords[2]->v);
393
394 result->grid_index = face_grid_coords[0]->grid_index;
395 result->u = lerp_f(v, u01, u32);
396 result->v = lerp_f(u, v03, v12);
397}
398
399static void foreach_toplevel_grid_coord(
400 const MultiresReshapeSmoothContext *reshape_smooth_context,
401 blender::FunctionRef<void(const PTexCoord *, const GridCoord *)> callback)
402{
403 using namespace blender;
404 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
405 const int level_difference = (reshape_context->top.level - reshape_context->reshape.level);
406
407 const int inner_grid_size = (1 << level_difference) + 1;
408 const float inner_grid_size_1_inv = 1.0f / float(inner_grid_size - 1);
409
410 const OffsetIndices<int> faces = reshape_smooth_context->geometry.faces();
411 threading::parallel_for(faces.index_range(), 1, [&](const IndexRange range) {
412 for (const int face_index : range) {
413 const blender::IndexRange face = faces[face_index];
414 const GridCoord *face_grid_coords[4];
415 grid_coords_from_face_verts(reshape_smooth_context, face, face_grid_coords);
416
417 for (int y = 0; y < inner_grid_size; ++y) {
418 const float ptex_v = float(y) * inner_grid_size_1_inv;
419 for (int x = 0; x < inner_grid_size; ++x) {
420 const float ptex_u = float(x) * inner_grid_size_1_inv;
421
422 PTexCoord ptex_coord;
423 ptex_coord.ptex_face_index = face_index;
424 ptex_coord.u = ptex_u;
425 ptex_coord.v = ptex_v;
426
427 GridCoord grid_coord;
428 interpolate_grid_coord(&grid_coord, face_grid_coords, ptex_u, ptex_v);
429
430 callback(&ptex_coord, &grid_coord);
431 }
432 }
433 }
434 });
435}
436
438
439/* -------------------------------------------------------------------- */
445
446static int get_reshape_level_resolution(const MultiresReshapeContext *reshape_context)
447{
448 return (1 << reshape_context->reshape.level) + 1;
449}
450
451static bool is_crease_supported(const MultiresReshapeSmoothContext *reshape_smooth_context)
452{
453 return !ELEM(reshape_smooth_context->smoothing_type,
456}
457
458/* Get crease which will be used for communication to OpenSubdiv topology.
459 * Note that simple subdivision treats all base edges as infinitely sharp. */
460static float get_effective_crease(const MultiresReshapeSmoothContext *reshape_smooth_context,
461 const int base_edge_index)
462{
463 if (!is_crease_supported(reshape_smooth_context)) {
464 return 1.0f;
465 }
466 if (reshape_smooth_context->reshape_context->cd_edge_crease.is_empty()) {
467 return 0.0f;
468 }
469 return reshape_smooth_context->reshape_context->cd_edge_crease[base_edge_index];
470}
471
472static float get_effective_crease_float(const MultiresReshapeSmoothContext *reshape_smooth_context,
473 const float crease)
474{
475 if (!is_crease_supported(reshape_smooth_context)) {
476 return 1.0f;
477 }
478 return crease;
479}
480
481static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context,
482 const MultiresReshapeContext *reshape_context,
483 const MultiresSubdivideModeType mode)
484{
485 reshape_smooth_context->reshape_context = reshape_context;
486
487 reshape_smooth_context->geometry.num_vertices = 0;
488 reshape_smooth_context->geometry.vertices = nullptr;
489
490 reshape_smooth_context->geometry.max_edges = 0;
491 reshape_smooth_context->geometry.num_edges = 0;
492 reshape_smooth_context->geometry.edges = nullptr;
493
494 reshape_smooth_context->geometry.num_corners = 0;
495 reshape_smooth_context->geometry.corners = nullptr;
496
497 reshape_smooth_context->geometry.num_faces = 0;
498
499 linear_grids_init(&reshape_smooth_context->linear_delta_grids);
500
501 reshape_smooth_context->loose_base_edges = {};
502 reshape_smooth_context->reshape_subdiv = nullptr;
503 reshape_smooth_context->base_surface_grids = nullptr;
504
505 reshape_smooth_context->smoothing_type = mode;
506}
507
508static void context_free_geometry(MultiresReshapeSmoothContext *reshape_smooth_context)
509{
510 if (reshape_smooth_context->geometry.vertices != nullptr) {
511 for (int i = 0; i < reshape_smooth_context->geometry.num_vertices; ++i) {
512 MEM_SAFE_FREE(reshape_smooth_context->geometry.vertices[i].grid_coords);
513 }
514 }
515 MEM_SAFE_FREE(reshape_smooth_context->geometry.vertices);
516 MEM_SAFE_FREE(reshape_smooth_context->geometry.corners);
517 reshape_smooth_context->geometry.face_offsets = {};
518 MEM_SAFE_FREE(reshape_smooth_context->geometry.edges);
519
520 linear_grids_free(&reshape_smooth_context->linear_delta_grids);
521}
522
523static void context_free_subdiv(MultiresReshapeSmoothContext *reshape_smooth_context)
524{
525 if (reshape_smooth_context->reshape_subdiv == nullptr) {
526 return;
527 }
528 blender::bke::subdiv::free(reshape_smooth_context->reshape_subdiv);
529}
530
531static void context_free(MultiresReshapeSmoothContext *reshape_smooth_context)
532{
533 context_free_geometry(reshape_smooth_context);
534 context_free_subdiv(reshape_smooth_context);
535 base_surface_grids_free(reshape_smooth_context);
536}
537
538static bool foreach_topology_info(const blender::bke::subdiv::ForeachContext *foreach_context,
539 const int num_vertices,
540 const int num_edges,
541 const int num_loops,
542 const int num_faces,
543 const int * /*subdiv_face_offset*/)
544{
545 MultiresReshapeSmoothContext *reshape_smooth_context =
546 static_cast<MultiresReshapeSmoothContext *>(foreach_context->user_data);
547 const int max_edges = reshape_smooth_context->smoothing_type ==
549 num_edges :
550 reshape_smooth_context->geometry.max_edges;
551
552 /* NOTE: Calloc so the counters are re-set to 0 "for free". */
553 reshape_smooth_context->geometry.num_vertices = num_vertices;
554 reshape_smooth_context->geometry.vertices = MEM_calloc_arrayN<Vertex>(num_vertices,
555 "smooth vertices");
556
557 reshape_smooth_context->geometry.max_edges = max_edges;
558 reshape_smooth_context->geometry.edges = MEM_malloc_arrayN<Edge>(size_t(max_edges),
559 "smooth edges");
560
561 reshape_smooth_context->geometry.num_corners = num_loops;
562 reshape_smooth_context->geometry.corners = MEM_malloc_arrayN<Corner>(size_t(num_loops),
563 "smooth corners");
564
565 reshape_smooth_context->geometry.num_faces = num_faces;
566 reshape_smooth_context->geometry.face_offsets.reinitialize(num_faces + 1);
567 reshape_smooth_context->geometry.face_offsets.last() = num_loops;
568
569 return true;
570}
571
572static void foreach_single_vertex(const blender::bke::subdiv::ForeachContext *foreach_context,
573 const GridCoord *grid_coord,
574 const int coarse_vertex_index,
575 const int subdiv_vertex_index)
576{
577 const MultiresReshapeSmoothContext *reshape_smooth_context =
578 static_cast<MultiresReshapeSmoothContext *>(foreach_context->user_data);
579
580 BLI_assert(subdiv_vertex_index < reshape_smooth_context->geometry.num_vertices);
581
582 Vertex *vertex = &reshape_smooth_context->geometry.vertices[subdiv_vertex_index];
583
584 vertex->grid_coords = static_cast<GridCoord *>(
585 MEM_reallocN(vertex->grid_coords, sizeof(Vertex) * (vertex->num_grid_coords + 1)));
586 vertex->grid_coords[vertex->num_grid_coords] = *grid_coord;
587 ++vertex->num_grid_coords;
588
589 if (coarse_vertex_index == -1) {
590 return;
591 }
592
593 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
594 if (reshape_context->cd_vertex_crease.is_empty()) {
595 return;
596 }
597
598 float crease = reshape_context->cd_vertex_crease[coarse_vertex_index];
599 if (crease == 0.0f) {
600 return;
601 }
602
603 crease = get_effective_crease_float(reshape_smooth_context, crease);
604 vertex->sharpness = blender::bke::subdiv::crease_to_sharpness(crease);
605}
606
607/* TODO(sergey): De-duplicate with similar function in multires_reshape_vertcos.cc */
608static void foreach_vertex(const blender::bke::subdiv::ForeachContext *foreach_context,
609 const PTexCoord *ptex_coord,
610 const int coarse_vertex_index,
611 const int subdiv_vertex_index)
612{
613 const MultiresReshapeSmoothContext *reshape_smooth_context =
614 static_cast<const MultiresReshapeSmoothContext *>(foreach_context->user_data);
615 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
616
617 const GridCoord grid_coord = multires_reshape_ptex_coord_to_grid(reshape_context, ptex_coord);
618 const int face_index = multires_reshape_grid_to_face_index(reshape_context,
619 grid_coord.grid_index);
620
621 const int num_corners = reshape_context->base_faces[face_index].size();
622 const int start_grid_index = reshape_context->face_start_grid_index[face_index];
623 const int corner = grid_coord.grid_index - start_grid_index;
624
625 if (grid_coord.u == 0.0f && grid_coord.v == 0.0f) {
626 for (int current_corner = 0; current_corner < num_corners; ++current_corner) {
627 GridCoord corner_grid_coord = grid_coord;
628 corner_grid_coord.grid_index = start_grid_index + current_corner;
629 foreach_single_vertex(
630 foreach_context, &corner_grid_coord, coarse_vertex_index, subdiv_vertex_index);
631 }
632 return;
633 }
634
635 foreach_single_vertex(foreach_context, &grid_coord, coarse_vertex_index, subdiv_vertex_index);
636
637 if (grid_coord.u == 0.0f) {
638 GridCoord prev_grid_coord;
639 prev_grid_coord.grid_index = start_grid_index + ((corner + num_corners - 1) % num_corners);
640 prev_grid_coord.u = grid_coord.v;
641 prev_grid_coord.v = 0.0f;
642
643 foreach_single_vertex(
644 foreach_context, &prev_grid_coord, coarse_vertex_index, subdiv_vertex_index);
645 }
646
647 if (grid_coord.v == 0.0f) {
648 GridCoord next_grid_coord;
649 next_grid_coord.grid_index = start_grid_index + ((corner + 1) % num_corners);
650 next_grid_coord.u = 0.0f;
651 next_grid_coord.v = grid_coord.u;
652
653 foreach_single_vertex(
654 foreach_context, &next_grid_coord, coarse_vertex_index, subdiv_vertex_index);
655 }
656}
657
658static void foreach_vertex_inner(const blender::bke::subdiv::ForeachContext *foreach_context,
659 void * /*tls*/,
660 const int ptex_face_index,
661 const float ptex_face_u,
662 const float ptex_face_v,
663 const int /*coarse_face_index*/,
664 const int /*coarse_corner*/,
665 const int subdiv_vertex_index)
666{
667 PTexCoord ptex_coord{};
668 ptex_coord.ptex_face_index = ptex_face_index;
669 ptex_coord.u = ptex_face_u;
670 ptex_coord.v = ptex_face_v;
671 foreach_vertex(foreach_context, &ptex_coord, -1, subdiv_vertex_index);
672}
673
674static void foreach_vertex_every_corner(
675 const blender::bke::subdiv::ForeachContext *foreach_context,
676 void * /*tls_v*/,
677 const int ptex_face_index,
678 const float ptex_face_u,
679 const float ptex_face_v,
680 const int coarse_vertex_index,
681 const int /*coarse_face_index*/,
682 const int /*coarse_face_corner*/,
683 const int subdiv_vertex_index)
684{
685 PTexCoord ptex_coord{};
686 ptex_coord.ptex_face_index = ptex_face_index;
687 ptex_coord.u = ptex_face_u;
688 ptex_coord.v = ptex_face_v;
689 foreach_vertex(foreach_context, &ptex_coord, coarse_vertex_index, subdiv_vertex_index);
690}
691
692static void foreach_vertex_every_edge(const blender::bke::subdiv::ForeachContext *foreach_context,
693 void * /*tls_v*/,
694 const int ptex_face_index,
695 const float ptex_face_u,
696 const float ptex_face_v,
697 const int /*coarse_edge_index*/,
698 const int /*coarse_face_index*/,
699 const int /*coarse_face_corner*/,
700 const int subdiv_vertex_index)
701{
702 PTexCoord ptex_coord{};
703 ptex_coord.ptex_face_index = ptex_face_index;
704 ptex_coord.u = ptex_face_u;
705 ptex_coord.v = ptex_face_v;
706 foreach_vertex(foreach_context, &ptex_coord, -1, subdiv_vertex_index);
707}
708
709static void foreach_loop(const blender::bke::subdiv::ForeachContext *foreach_context,
710 void * /*tls*/,
711 const int /*ptex_face_index*/,
712 const float /*ptex_face_u*/,
713 const float /*ptex_face_v*/,
714 const int /*coarse_loop_index*/,
715 const int coarse_face_index,
716 const int coarse_corner,
717 const int subdiv_loop_index,
718 const int subdiv_vertex_index,
719 const int /*subdiv_edge_index*/)
720{
721 const MultiresReshapeSmoothContext *reshape_smooth_context =
722 static_cast<const MultiresReshapeSmoothContext *>(foreach_context->user_data);
723 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
724
725 BLI_assert(subdiv_loop_index < reshape_smooth_context->geometry.num_corners);
726
727 Corner *corner = &reshape_smooth_context->geometry.corners[subdiv_loop_index];
728 corner->vertex = &reshape_smooth_context->geometry.vertices[subdiv_vertex_index];
729
730 const int first_grid_index = reshape_context->face_start_grid_index[coarse_face_index];
731 corner->grid_index = first_grid_index + coarse_corner;
732}
733
734static void foreach_poly(const blender::bke::subdiv::ForeachContext *foreach_context,
735 void * /*tls*/,
736 const int /*coarse_face_index*/,
737 const int subdiv_face_index,
738 const int start_loop_index,
739 const int /*num_loops*/)
740{
741 MultiresReshapeSmoothContext *reshape_smooth_context =
742 static_cast<MultiresReshapeSmoothContext *>(foreach_context->user_data);
743
744 BLI_assert(subdiv_face_index < reshape_smooth_context->geometry.num_faces);
745
746 reshape_smooth_context->geometry.face_offsets[subdiv_face_index] = start_loop_index;
747}
748
749static void foreach_vertex_of_loose_edge(
750 const blender::bke::subdiv::ForeachContext *foreach_context,
751 void * /*tls*/,
752 const int /*coarse_edge_index*/,
753 const float /*u*/,
754 const int vertex_index)
755{
756 const MultiresReshapeSmoothContext *reshape_smooth_context =
757 static_cast<const MultiresReshapeSmoothContext *>(foreach_context->user_data);
758 Vertex *vertex = &reshape_smooth_context->geometry.vertices[vertex_index];
759
760 if (vertex->num_grid_coords != 0) {
761 vertex->is_infinite_sharp = true;
762 }
763}
764
765static void store_edge(MultiresReshapeSmoothContext *reshape_smooth_context,
766 const int subdiv_v1,
767 const int subdiv_v2,
768 const float crease)
769{
770 /* This is a bit overhead to use atomics in such a simple function called from many threads,
771 * but this allows to save quite measurable amount of memory. */
772 const int edge_index = atomic_fetch_and_add_z(&reshape_smooth_context->geometry.num_edges, 1);
773 BLI_assert(edge_index < reshape_smooth_context->geometry.max_edges);
774
775 Edge *edge = &reshape_smooth_context->geometry.edges[edge_index];
776 edge->v1 = subdiv_v1;
777 edge->v2 = subdiv_v2;
778 edge->sharpness = blender::bke::subdiv::crease_to_sharpness(crease);
779}
780
781static void foreach_edge(const blender::bke::subdiv::ForeachContext *foreach_context,
782 void * /*tls*/,
783 const int coarse_edge_index,
784 const int /*subdiv_edge_index*/,
785 const bool is_loose,
786 const int subdiv_v1,
787 const int subdiv_v2)
788{
789 MultiresReshapeSmoothContext *reshape_smooth_context =
790 static_cast<MultiresReshapeSmoothContext *>(foreach_context->user_data);
791
792 if (reshape_smooth_context->smoothing_type == MultiresSubdivideModeType::Linear) {
793 if (!is_loose) {
794 store_edge(reshape_smooth_context, subdiv_v1, subdiv_v2, 1.0f);
795 }
796 return;
797 }
798
799 /* Ignore all inner face edges as they have sharpness of zero. */
800 if (coarse_edge_index == ORIGINDEX_NONE) {
801 return;
802 }
803 /* Ignore all loose edges as well, as they are not communicated to the OpenSubdiv. */
804 if (!reshape_smooth_context->loose_base_edges.is_empty()) {
805 if (reshape_smooth_context->loose_base_edges[coarse_edge_index]) {
806 return;
807 }
808 }
809 /* Edges without crease are to be ignored as well. */
810 const float crease = get_effective_crease(reshape_smooth_context, coarse_edge_index);
811 if (crease == 0.0f) {
812 return;
813 }
814 store_edge(reshape_smooth_context, subdiv_v1, subdiv_v2, crease);
815}
816
817static void geometry_init_loose_information(MultiresReshapeSmoothContext *reshape_smooth_context)
818{
819 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
820 const Mesh *base_mesh = reshape_context->base_mesh;
821
822 const blender::bke::LooseEdgeCache &loose_edges = base_mesh->loose_edges();
823 reshape_smooth_context->loose_base_edges = loose_edges.is_loose_bits;
824
825 int num_used_edges = 0;
826 for (const int edge : blender::IndexRange(base_mesh->edges_num)) {
827 if (loose_edges.count > 0 && loose_edges.is_loose_bits[edge]) {
828 continue;
829 }
830 const float crease = get_effective_crease(reshape_smooth_context, edge);
831 if (crease == 0.0f) {
832 continue;
833 }
834 num_used_edges++;
835 }
836
837 const int resolution = get_reshape_level_resolution(reshape_context);
838 const int num_subdiv_vertices_per_base_edge = resolution - 2;
839 reshape_smooth_context->geometry.max_edges = num_used_edges *
840 (num_subdiv_vertices_per_base_edge + 1);
841}
842
843static void geometry_create(MultiresReshapeSmoothContext *reshape_smooth_context)
844{
845 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
846
847 blender::bke::subdiv::ForeachContext foreach_context{};
848 foreach_context.topology_info = foreach_topology_info;
849 foreach_context.vertex_inner = foreach_vertex_inner;
850 foreach_context.vertex_every_corner = foreach_vertex_every_corner;
851 foreach_context.vertex_every_edge = foreach_vertex_every_edge;
852 foreach_context.loop = foreach_loop;
853 foreach_context.poly = foreach_poly;
854 foreach_context.vertex_of_loose_edge = foreach_vertex_of_loose_edge;
855 foreach_context.edge = foreach_edge;
856 foreach_context.user_data = reshape_smooth_context;
857
858 geometry_init_loose_information(reshape_smooth_context);
859
861 mesh_settings.resolution = get_reshape_level_resolution(reshape_context);
862 mesh_settings.use_optimal_display = false;
863
864 /* TODO(sergey): Tell the foreach() to ignore loose vertices. */
866 reshape_context->subdiv, &foreach_context, &mesh_settings, reshape_context->base_mesh);
867}
868
870
871/* -------------------------------------------------------------------- */
874
875static OpenSubdiv_SchemeType get_scheme_type(const OpenSubdiv_Converter * /*converter*/)
876{
877 return OSD_SCHEME_CATMARK;
878}
879
880static OpenSubdiv_VtxBoundaryInterpolation get_vtx_boundary_interpolation(
881 const OpenSubdiv_Converter *converter)
882{
883 const MultiresReshapeSmoothContext *reshape_smooth_context =
884 static_cast<const MultiresReshapeSmoothContext *>(converter->user_data);
885 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
886 const blender::bke::subdiv::Settings *settings = &reshape_context->subdiv->settings;
887
890}
891
892static OpenSubdiv_FVarLinearInterpolation get_fvar_linear_interpolation(
893 const OpenSubdiv_Converter *converter)
894{
895 const MultiresReshapeSmoothContext *reshape_smooth_context =
896 static_cast<const MultiresReshapeSmoothContext *>(converter->user_data);
897 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
898 const blender::bke::subdiv::Settings *settings = &reshape_context->subdiv->settings;
899
902}
903
904static bool specifies_full_topology(const OpenSubdiv_Converter * /*converter*/)
905{
906 return false;
907}
908
909static int get_num_vertices(const OpenSubdiv_Converter *converter)
910{
911 const MultiresReshapeSmoothContext *reshape_smooth_context =
912 static_cast<const MultiresReshapeSmoothContext *>(converter->user_data);
913
914 return reshape_smooth_context->geometry.num_vertices;
915}
916
917static void get_face_vertices(const OpenSubdiv_Converter *converter,
918 int face_index,
919 int *face_vertices)
920{
921 const MultiresReshapeSmoothContext *reshape_smooth_context =
922 static_cast<const MultiresReshapeSmoothContext *>(converter->user_data);
923 BLI_assert(face_index < reshape_smooth_context->geometry.num_faces);
924
925 const blender::IndexRange face = reshape_smooth_context->geometry.faces()[face_index];
926
927 for (const int i : face.index_range()) {
928 const int corner_index = face[i];
929 const Corner *corner = &reshape_smooth_context->geometry.corners[corner_index];
930 face_vertices[i] = corner->vertex - reshape_smooth_context->geometry.vertices;
931 }
932}
933
934static int get_num_edges(const OpenSubdiv_Converter *converter)
935{
936 const MultiresReshapeSmoothContext *reshape_smooth_context =
937 static_cast<const MultiresReshapeSmoothContext *>(converter->user_data);
938 return reshape_smooth_context->geometry.num_edges;
939}
940
941static void get_edge_vertices(const OpenSubdiv_Converter *converter,
942 const int edge_index,
943 int edge_vertices[2])
944{
945 const MultiresReshapeSmoothContext *reshape_smooth_context =
946 static_cast<const MultiresReshapeSmoothContext *>(converter->user_data);
947 BLI_assert(edge_index < reshape_smooth_context->geometry.num_edges);
948
949 const Edge *edge = &reshape_smooth_context->geometry.edges[edge_index];
950 edge_vertices[0] = edge->v1;
951 edge_vertices[1] = edge->v2;
952}
953
954static float get_edge_sharpness(const OpenSubdiv_Converter *converter, const int edge_index)
955{
956 const MultiresReshapeSmoothContext *reshape_smooth_context =
957 static_cast<const MultiresReshapeSmoothContext *>(converter->user_data);
958 BLI_assert(edge_index < reshape_smooth_context->geometry.num_edges);
959
960 const Edge *edge = &reshape_smooth_context->geometry.edges[edge_index];
961 return edge->sharpness;
962}
963
964static float get_vertex_sharpness(const OpenSubdiv_Converter *converter, const int vertex_index)
965{
966 const MultiresReshapeSmoothContext *reshape_smooth_context =
967 static_cast<const MultiresReshapeSmoothContext *>(converter->user_data);
968 BLI_assert(vertex_index < reshape_smooth_context->geometry.num_vertices);
969
970 const Vertex *vertex = &reshape_smooth_context->geometry.vertices[vertex_index];
971 return vertex->sharpness;
972}
973
974static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter, int vertex_index)
975{
976 const MultiresReshapeSmoothContext *reshape_smooth_context =
977 static_cast<const MultiresReshapeSmoothContext *>(converter->user_data);
978
979 BLI_assert(vertex_index < reshape_smooth_context->geometry.num_vertices);
980
981 const Vertex *vertex = &reshape_smooth_context->geometry.vertices[vertex_index];
982 return vertex->is_infinite_sharp;
983}
984
985static void converter_init(const MultiresReshapeSmoothContext *reshape_smooth_context,
986 OpenSubdiv_Converter *converter)
987{
988 converter->getSchemeType = get_scheme_type;
989 converter->getVtxBoundaryInterpolation = get_vtx_boundary_interpolation;
990 converter->getFVarLinearInterpolation = get_fvar_linear_interpolation;
991 converter->specifiesFullTopology = specifies_full_topology;
992
993 converter->faces = reshape_smooth_context->geometry.faces();
994
995 converter->getNumEdges = get_num_edges;
996 converter->getNumVertices = get_num_vertices;
997
998 converter->getFaceVertices = get_face_vertices;
999 converter->getFaceEdges = nullptr;
1000
1001 converter->getEdgeVertices = get_edge_vertices;
1002 converter->getNumEdgeFaces = nullptr;
1003 converter->getEdgeFaces = nullptr;
1004 converter->getEdgeSharpness = get_edge_sharpness;
1005
1006 converter->getNumVertexEdges = nullptr;
1007 converter->getVertexEdges = nullptr;
1008 converter->getNumVertexFaces = nullptr;
1009 converter->getVertexFaces = nullptr;
1010 converter->isInfiniteSharpVertex = is_infinite_sharp_vertex;
1011 converter->getVertexSharpness = get_vertex_sharpness;
1012
1013 converter->getNumUVLayers = nullptr;
1014 converter->precalcUVLayer = nullptr;
1015 converter->finishUVLayer = nullptr;
1016 converter->getNumUVCoordinates = nullptr;
1017 converter->getFaceCornerUVIndex = nullptr;
1018
1019 converter->freeUserData = nullptr;
1020
1021 converter->user_data = (void *)reshape_smooth_context;
1022}
1023
1024/* Create subdiv descriptor created for topology at a reshape level. */
1025static void reshape_subdiv_create(MultiresReshapeSmoothContext *reshape_smooth_context)
1026{
1027 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1028 const blender::bke::subdiv::Settings *settings = &reshape_context->subdiv->settings;
1029
1030 OpenSubdiv_Converter converter;
1031 converter_init(reshape_smooth_context, &converter);
1032
1034 settings, &converter);
1035
1036 OpenSubdiv_EvaluatorSettings evaluator_settings = {0};
1037 blender::bke::subdiv::eval_begin(reshape_subdiv,
1039 nullptr,
1040 &evaluator_settings);
1041
1042 reshape_smooth_context->reshape_subdiv = reshape_subdiv;
1043
1045}
1046
1047/* Callback to provide coarse position for subdivision surface topology at a reshape level. */
1048using ReshapeSubdivCoarsePositionCb =
1049 void(const MultiresReshapeSmoothContext *reshape_smooth_context,
1050 const Vertex *vertex,
1051 float r_P[3]);
1052
1053/* Refine subdivision surface topology at a reshape level for new coarse vertices positions. */
1054static void reshape_subdiv_refine(const MultiresReshapeSmoothContext *reshape_smooth_context,
1055 ReshapeSubdivCoarsePositionCb coarse_position_cb)
1056{
1057 blender::bke::subdiv::Subdiv *reshape_subdiv = reshape_smooth_context->reshape_subdiv;
1058
1059 /* TODO(sergey): For non-trivial coarse_position_cb we should multi-thread this loop. */
1060
1061 const int num_vertices = reshape_smooth_context->geometry.num_vertices;
1062 for (int i = 0; i < num_vertices; ++i) {
1063 const Vertex *vertex = &reshape_smooth_context->geometry.vertices[i];
1064 float P[3];
1065 coarse_position_cb(reshape_smooth_context, vertex, P);
1066 reshape_subdiv->evaluator->eval_output->setCoarsePositions(P, i, 1);
1067 }
1068 reshape_subdiv->evaluator->eval_output->refine();
1069}
1070
1071BLI_INLINE const GridCoord *reshape_subdiv_refine_vertex_grid_coord(const Vertex *vertex)
1072{
1073 if (vertex->num_grid_coords == 0) {
1074 /* This is a loose vertex, the coordinate is not important. */
1075 /* TODO(sergey): Once the subdiv_foreach() supports properly ignoring loose elements this
1076 * should become an assert instead. */
1077 return nullptr;
1078 }
1079 /* NOTE: All grid coordinates will point to the same object position, so can be simple and use
1080 * first grid coordinate. */
1081 return &vertex->grid_coords[0];
1082}
1083
1084/* Version of reshape_subdiv_refine() which uses coarse position from original grids. */
1085static void reshape_subdiv_refine_orig_P(
1086 const MultiresReshapeSmoothContext *reshape_smooth_context, const Vertex *vertex, float r_P[3])
1087{
1088 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1089 const GridCoord *grid_coord = reshape_subdiv_refine_vertex_grid_coord(vertex);
1090
1091 /* Check whether this is a loose vertex. */
1092 if (grid_coord == nullptr) {
1093 zero_v3(r_P);
1094 return;
1095 }
1096
1097 float limit_P[3];
1098 float tangent_matrix[3][3];
1099 multires_reshape_evaluate_limit_at_grid(reshape_context, grid_coord, limit_P, tangent_matrix);
1100
1101 const ReshapeConstGridElement orig_grid_element =
1102 multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord);
1103
1104 float D[3];
1105 mul_v3_m3v3(D, tangent_matrix, orig_grid_element.displacement);
1106
1107 add_v3_v3v3(r_P, limit_P, D);
1108}
1109static void reshape_subdiv_refine_orig(const MultiresReshapeSmoothContext *reshape_smooth_context)
1110{
1111 reshape_subdiv_refine(reshape_smooth_context, reshape_subdiv_refine_orig_P);
1112}
1113
1114/* Version of reshape_subdiv_refine() which uses coarse position from final grids. */
1115static void reshape_subdiv_refine_final_P(
1116 const MultiresReshapeSmoothContext *reshape_smooth_context, const Vertex *vertex, float r_P[3])
1117{
1118 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1119 const GridCoord *grid_coord = reshape_subdiv_refine_vertex_grid_coord(vertex);
1120
1121 /* Check whether this is a loose vertex. */
1122 if (grid_coord == nullptr) {
1123 zero_v3(r_P);
1124 return;
1125 }
1126
1128 reshape_context, grid_coord);
1129
1130 /* NOTE: At this point in reshape/propagate pipeline grid displacement is actually storing object
1131 * vertices coordinates. */
1132 copy_v3_v3(r_P, grid_element.displacement);
1133}
1134static void reshape_subdiv_refine_final(const MultiresReshapeSmoothContext *reshape_smooth_context)
1135{
1136 reshape_subdiv_refine(reshape_smooth_context, reshape_subdiv_refine_final_P);
1137}
1138
1139static void reshape_subdiv_evaluate_limit_at_grid(
1140 const MultiresReshapeSmoothContext *reshape_smooth_context,
1141 const PTexCoord *ptex_coord,
1142 const GridCoord *grid_coord,
1143 float limit_P[3],
1144 float r_tangent_matrix[3][3])
1145{
1146 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1147
1148 float dPdu[3], dPdv[3];
1149 blender::bke::subdiv::eval_limit_point_and_derivatives(reshape_smooth_context->reshape_subdiv,
1150 ptex_coord->ptex_face_index,
1151 ptex_coord->u,
1152 ptex_coord->v,
1153 limit_P,
1154 dPdu,
1155 dPdv);
1156
1157 const int face_index = multires_reshape_grid_to_face_index(reshape_context,
1158 grid_coord->grid_index);
1159 const int corner = multires_reshape_grid_to_corner(reshape_context, grid_coord->grid_index);
1161 reshape_context, face_index, corner, dPdu, dPdv, r_tangent_matrix);
1162}
1163
1165
1166/* -------------------------------------------------------------------- */
1169
1170static LinearGridElement linear_grid_element_orig_get(
1171 const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord)
1172{
1173 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1174 const ReshapeConstGridElement orig_grid_element =
1175 multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord);
1176
1177 LinearGridElement linear_grid_element;
1178 linear_grid_element_init(&linear_grid_element);
1179
1180 linear_grid_element.mask = orig_grid_element.mask;
1181
1182 return linear_grid_element;
1183}
1184
1185static LinearGridElement linear_grid_element_final_get(
1186 const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord)
1187{
1188 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1190 reshape_context, grid_coord);
1191
1192 LinearGridElement linear_grid_element;
1193 linear_grid_element_init(&linear_grid_element);
1194
1195 if (final_grid_element.mask != nullptr) {
1196 linear_grid_element.mask = *final_grid_element.mask;
1197 }
1198
1199 return linear_grid_element;
1200}
1201
1202/* Interpolate difference of the linear data.
1203 *
1204 * Will access final data and original data at the grid elements at the reshape level,
1205 * calculate difference between final and original, and linearly interpolate to get value at the
1206 * top level. */
1207static void linear_grid_element_delta_interpolate(
1208 const MultiresReshapeSmoothContext *reshape_smooth_context,
1209 const GridCoord *grid_coord,
1210 LinearGridElement *result)
1211{
1212 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1213
1214 const int reshape_level = reshape_context->reshape.level;
1215 const int reshape_level_grid_size = blender::bke::subdiv::grid_size_from_level(reshape_level);
1216 const int reshape_level_grid_size_1 = reshape_level_grid_size - 1;
1217 const float reshape_level_grid_size_1_inv = 1.0f / float(reshape_level_grid_size_1);
1218
1219 const float x_f = grid_coord->u * reshape_level_grid_size_1;
1220 const float y_f = grid_coord->v * reshape_level_grid_size_1;
1221
1222 const int x_i = x_f;
1223 const int y_i = y_f;
1224 const int x_n_i = (x_i == reshape_level_grid_size - 1) ? (x_i) : (x_i + 1);
1225 const int y_n_i = (y_i == reshape_level_grid_size - 1) ? (y_i) : (y_i + 1);
1226
1227 const int corners_int_coords[4][2] = {{x_i, y_i}, {x_n_i, y_i}, {x_n_i, y_n_i}, {x_i, y_n_i}};
1228
1229 LinearGridElement corner_elements[4];
1230 for (int i = 0; i < 4; ++i) {
1231 GridCoord corner_grid_coord;
1232 corner_grid_coord.grid_index = grid_coord->grid_index;
1233 corner_grid_coord.u = corners_int_coords[i][0] * reshape_level_grid_size_1_inv;
1234 corner_grid_coord.v = corners_int_coords[i][1] * reshape_level_grid_size_1_inv;
1235
1236 const LinearGridElement orig_element = linear_grid_element_orig_get(reshape_smooth_context,
1237 &corner_grid_coord);
1238 const LinearGridElement final_element = linear_grid_element_final_get(reshape_smooth_context,
1239 &corner_grid_coord);
1240 linear_grid_element_sub(&corner_elements[i], &final_element, &orig_element);
1241 }
1242
1243 const float u = x_f - x_i;
1244 const float v = y_f - y_i;
1245 const float weights[4] = {(1.0f - u) * (1.0f - v), u * (1.0f - v), u * v, (1.0f - u) * v};
1246
1247 linear_grid_element_interpolate(result, corner_elements, weights);
1248}
1249
1250static void evaluate_linear_delta_grids(MultiresReshapeSmoothContext *reshape_smooth_context)
1251{
1252 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1253 const int num_grids = reshape_context->num_grids;
1254 const int top_level = reshape_context->top.level;
1255
1256 linear_grids_allocate(&reshape_smooth_context->linear_delta_grids, num_grids, top_level);
1257
1258 foreach_toplevel_grid_coord(reshape_smooth_context,
1259 [&](const PTexCoord * /*ptex_coord*/, const GridCoord *grid_coord) {
1260 LinearGridElement *linear_delta_element = linear_grid_element_get(
1261 &reshape_smooth_context->linear_delta_grids, grid_coord);
1262
1263 linear_grid_element_delta_interpolate(
1264 reshape_smooth_context, grid_coord, linear_delta_element);
1265 });
1266}
1267
1268static void propagate_linear_data_delta(const MultiresReshapeSmoothContext *reshape_smooth_context,
1269 ReshapeGridElement *final_grid_element,
1270 const GridCoord *grid_coord)
1271{
1272 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1273
1274 LinearGridElement *linear_delta_element = linear_grid_element_get(
1275 &reshape_smooth_context->linear_delta_grids, grid_coord);
1276
1277 const ReshapeConstGridElement orig_grid_element =
1278 multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord);
1279
1280 if (final_grid_element->mask != nullptr) {
1281 *final_grid_element->mask = clamp_f(
1282 orig_grid_element.mask + linear_delta_element->mask, 0.0f, 1.0f);
1283 }
1284}
1285
1287
1288/* -------------------------------------------------------------------- */
1291
1292static void evaluate_base_surface_grids(const MultiresReshapeSmoothContext *reshape_smooth_context)
1293{
1294 foreach_toplevel_grid_coord(
1295 reshape_smooth_context, [&](const PTexCoord *ptex_coord, const GridCoord *grid_coord) {
1296 float limit_P[3];
1297 float tangent_matrix[3][3];
1298 reshape_subdiv_evaluate_limit_at_grid(
1299 reshape_smooth_context, ptex_coord, grid_coord, limit_P, tangent_matrix);
1300
1301 base_surface_grids_write(reshape_smooth_context, grid_coord, limit_P, tangent_matrix);
1302 });
1303}
1304
1306
1307/* -------------------------------------------------------------------- */
1310
1311/* Evaluate final position of the original (pre-sculpt-edit) point position at a given grid
1312 * coordinate. */
1313static void evaluate_final_original_point(
1314 const MultiresReshapeSmoothContext *reshape_smooth_context,
1315 const GridCoord *grid_coord,
1316 float r_orig_final_P[3])
1317{
1318 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1319
1320 /* Element of an original MDISPS grid) */
1321 const ReshapeConstGridElement orig_grid_element =
1322 multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord);
1323
1324 /* Limit surface of the base mesh. */
1325 float base_mesh_limit_P[3];
1326 float base_mesh_tangent_matrix[3][3];
1328 reshape_context, grid_coord, base_mesh_limit_P, base_mesh_tangent_matrix);
1329
1330 /* Convert original displacement from tangent space to object space. */
1331 float orig_displacement[3];
1332 mul_v3_m3v3(orig_displacement, base_mesh_tangent_matrix, orig_grid_element.displacement);
1333
1334 /* Final point = limit surface + displacement. */
1335 add_v3_v3v3(r_orig_final_P, base_mesh_limit_P, orig_displacement);
1336}
1337
1338static void evaluate_higher_grid_positions_with_details(
1339 const MultiresReshapeSmoothContext *reshape_smooth_context)
1340{
1341 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1342 foreach_toplevel_grid_coord(
1343 reshape_smooth_context, [&](const PTexCoord *ptex_coord, const GridCoord *grid_coord) {
1344 /* Position of the original vertex at top level. */
1345 float orig_final_P[3];
1346 evaluate_final_original_point(reshape_smooth_context, grid_coord, orig_final_P);
1347
1348 /* Original surface point on sculpt level (sculpt level before edits in sculpt mode). */
1349 const SurfacePoint *orig_sculpt_point = base_surface_grids_read(reshape_smooth_context,
1350 grid_coord);
1351
1352 /* Difference between original top level and original sculpt level in object space. */
1353 float original_detail_delta[3];
1354 sub_v3_v3v3(original_detail_delta, orig_final_P, orig_sculpt_point->P);
1355
1356 /* Difference between original top level and original sculpt level in tangent space of
1357 * original sculpt level. */
1358 float original_detail_delta_tangent[3];
1359 float original_sculpt_tangent_matrix_inv[3][3];
1360 invert_m3_m3(original_sculpt_tangent_matrix_inv, orig_sculpt_point->tangent_matrix);
1361 mul_v3_m3v3(original_detail_delta_tangent,
1362 original_sculpt_tangent_matrix_inv,
1363 original_detail_delta);
1364
1365 /* Limit surface of smoothed (subdivided) edited sculpt level. */
1366 float smooth_limit_P[3];
1367 float smooth_tangent_matrix[3][3];
1368 reshape_subdiv_evaluate_limit_at_grid(
1369 reshape_smooth_context, ptex_coord, grid_coord, smooth_limit_P, smooth_tangent_matrix);
1370
1371 /* Add original detail to the smoothed surface. */
1372 float smooth_delta[3];
1373 mul_v3_m3v3(smooth_delta, smooth_tangent_matrix, original_detail_delta_tangent);
1374
1375 /* Grid element of the result.
1376 *
1377 * NOTE: Displacement is storing object space coordinate. */
1379 reshape_context, grid_coord);
1380
1381 add_v3_v3v3(grid_element.displacement, smooth_limit_P, smooth_delta);
1382
1383 /* Propagate non-coordinate data. */
1384 propagate_linear_data_delta(reshape_smooth_context, &grid_element, grid_coord);
1385 });
1386}
1387
1388static void evaluate_higher_grid_positions(
1389 const MultiresReshapeSmoothContext *reshape_smooth_context)
1390{
1391 const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
1392 foreach_toplevel_grid_coord(
1393 reshape_smooth_context, [&](const PTexCoord *ptex_coord, const GridCoord *grid_coord) {
1394 blender::bke::subdiv::Subdiv *reshape_subdiv = reshape_smooth_context->reshape_subdiv;
1395
1397 reshape_context, grid_coord);
1398
1399 /* Surface. */
1400 float P[3];
1402 reshape_subdiv, ptex_coord->ptex_face_index, ptex_coord->u, ptex_coord->v, P);
1403
1404 copy_v3_v3(grid_element.displacement, P);
1405
1406 /* Propagate non-coordinate data. */
1407 propagate_linear_data_delta(reshape_smooth_context, &grid_element, grid_coord);
1408 });
1409}
1410
1411#endif
1412
1414
1415/* -------------------------------------------------------------------- */
1418
1420 const MultiresReshapeContext *reshape_context)
1421{
1422#ifdef WITH_OPENSUBDIV
1423 const int level_difference = (reshape_context->top.level - reshape_context->reshape.level);
1424 if (level_difference == 0) {
1425 /* Early output. */
1426 return;
1427 }
1428
1429 MultiresReshapeSmoothContext reshape_smooth_context;
1430 if (reshape_context->subdiv->settings.is_simple) {
1431 context_init(&reshape_smooth_context, reshape_context, MultiresSubdivideModeType::Simple);
1432 }
1433 else {
1434 context_init(
1435 &reshape_smooth_context, reshape_context, MultiresSubdivideModeType::CatmullClark);
1436 }
1437
1438 geometry_create(&reshape_smooth_context);
1439 evaluate_linear_delta_grids(&reshape_smooth_context);
1440
1441 reshape_subdiv_create(&reshape_smooth_context);
1442
1443 base_surface_grids_allocate(&reshape_smooth_context);
1444 reshape_subdiv_refine_orig(&reshape_smooth_context);
1445 evaluate_base_surface_grids(&reshape_smooth_context);
1446
1447 reshape_subdiv_refine_final(&reshape_smooth_context);
1448 evaluate_higher_grid_positions_with_details(&reshape_smooth_context);
1449
1450 context_free(&reshape_smooth_context);
1451#else
1452 UNUSED_VARS(reshape_context);
1453#endif
1454}
1455
1457 const MultiresSubdivideModeType mode)
1458{
1459#ifdef WITH_OPENSUBDIV
1460 const int level_difference = (reshape_context->top.level - reshape_context->reshape.level);
1461 if (level_difference == 0) {
1462 /* Early output. */
1463 return;
1464 }
1465
1466 MultiresReshapeSmoothContext reshape_smooth_context;
1467 context_init(&reshape_smooth_context, reshape_context, mode);
1468
1469 geometry_create(&reshape_smooth_context);
1470 evaluate_linear_delta_grids(&reshape_smooth_context);
1471
1472 reshape_subdiv_create(&reshape_smooth_context);
1473
1474 reshape_subdiv_refine_final(&reshape_smooth_context);
1475 evaluate_higher_grid_positions(&reshape_smooth_context);
1476
1477 context_free(&reshape_smooth_context);
1478#else
1479 UNUSED_VARS(reshape_context, mode);
1480#endif
1481}
1482
CustomData interface, see also DNA_customdata_types.h.
#define ORIGINDEX_NONE
MultiresSubdivideModeType
#define D
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_INLINE
MINLINE float clamp_f(float value, float min, float max)
void copy_m3_m3(float m1[3][3], const float m2[3][3])
bool invert_m3_m3(float inverse[3][3], const float mat[3][3])
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void zero_v3(float r[3])
#define UNUSED_VARS(...)
#define ELEM(...)
Read Guarded memory(de)allocation.
Provides wrapper around system-specific atomic primitives, and some extensions (faked-atomic operatio...
ATOMIC_INLINE size_t atomic_fetch_and_add_z(size_t *p, size_t x)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
constexpr bool is_empty() const
Definition BLI_span.hh:260
constexpr int64_t size() const
constexpr int64_t start() const
constexpr IndexRange index_range() const
void setCoarsePositions(const float *positions, const int start_vertex_index, const int num_vertices)
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
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
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static char faces[256]
int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_context, int grid_index)
ReshapeGridElement multires_reshape_grid_element_for_grid_coord(const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord)
void multires_reshape_tangent_matrix_for_corner(const MultiresReshapeContext *reshape_context, int face_index, int corner, const float dPdu[3], const float dPdv[3], float r_tangent_matrix[3][3])
int multires_reshape_grid_to_corner(const MultiresReshapeContext *reshape_context, int grid_index)
ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord(const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord)
GridCoord multires_reshape_ptex_coord_to_grid(const MultiresReshapeContext *reshape_context, const PTexCoord *ptex_coord)
void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord, float r_P[3], float r_tangent_matrix[3][3])
void multires_reshape_smooth_object_grids_with_details(const MultiresReshapeContext *reshape_context)
void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context, const MultiresSubdivideModeType mode)
void free(Subdiv *subdiv)
Definition subdiv.cc:190
BLI_INLINE float crease_to_sharpness(float crease)
int converter_fvar_linear_from_settings(const Settings *settings)
bool foreach_subdiv_geometry(Subdiv *subdiv, const ForeachContext *context, const ToMeshSettings *mesh_settings, const Mesh *coarse_mesh)
void eval_limit_point(Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[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])
int converter_vtx_boundary_interpolation_from_settings(const Settings *settings)
bool eval_begin(Subdiv *subdiv, eSubdivEvaluatorType evaluator_type, OpenSubdiv_EvaluatorCache *evaluator_cache, const OpenSubdiv_EvaluatorSettings *settings)
BLI_INLINE int grid_size_from_level(int level)
Subdiv * new_from_converter(const Settings *settings, OpenSubdiv_Converter *converter)
Definition subdiv.cc:98
void converter_free(OpenSubdiv_Converter *converter)
std::array< VecBase< T, 3 >, 8 > corners(const Bounds< VecBase< T, 3 > > &bounds)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
OpenSubdiv_FVarLinearInterpolation
OpenSubdiv_VtxBoundaryInterpolation
OpenSubdiv_SchemeType
@ OSD_SCHEME_CATMARK
int edges_num
blender::bke::subdiv::Subdiv * subdiv
blender::VArraySpan< float > cd_vertex_crease
blender::OffsetIndices< int > base_faces
struct MultiresReshapeContext::@211325377142251356170051242004336165165277317332 reshape
struct MultiresReshapeContext::@211264142214320354014015357273374070352161135110 top
int(* getFaceCornerUVIndex)(const OpenSubdiv_Converter *converter, const int face_index, const int corner_index)
void(* freeUserData)(const OpenSubdiv_Converter *converter)
int(* getNumEdges)(const OpenSubdiv_Converter *converter)
void(* precalcUVLayer)(const OpenSubdiv_Converter *converter, const int layer_index)
float(* getEdgeSharpness)(const OpenSubdiv_Converter *converter, const int edge_index)
int(* getNumVertexFaces)(const OpenSubdiv_Converter *converter, const int vertex_index)
void(* getVertexFaces)(const OpenSubdiv_Converter *converter, const int vertex_index, int *vertex_faces)
void(* getVertexEdges)(const OpenSubdiv_Converter *converter, const int vertex_index, int *vertex_edges)
OpenSubdiv_FVarLinearInterpolation(* getFVarLinearInterpolation)(const OpenSubdiv_Converter *converter)
bool(* specifiesFullTopology)(const OpenSubdiv_Converter *converter)
int(* getNumUVCoordinates)(const OpenSubdiv_Converter *converter)
void(* getFaceVertices)(const OpenSubdiv_Converter *converter, const int face_index, int *face_vertices)
OpenSubdiv_VtxBoundaryInterpolation(* getVtxBoundaryInterpolation)(const OpenSubdiv_Converter *converter)
int(* getNumUVLayers)(const OpenSubdiv_Converter *converter)
int(* getNumEdgeFaces)(const OpenSubdiv_Converter *converter, const int edge_index)
blender::OffsetIndices< int > faces
bool(* isInfiniteSharpVertex)(const OpenSubdiv_Converter *converter, const int vertex_index)
float(* getVertexSharpness)(const OpenSubdiv_Converter *converter, const int vertex_index)
OpenSubdiv_SchemeType(* getSchemeType)(const OpenSubdiv_Converter *converter)
void(* getEdgeVertices)(const OpenSubdiv_Converter *converter, const int edge_index, int edge_vertices[2])
int(* getNumVertexEdges)(const OpenSubdiv_Converter *converter, const int vertex_index)
int(* getNumVertices)(const OpenSubdiv_Converter *converter)
void(* getFaceEdges)(const OpenSubdiv_Converter *converter, const int face_index, int *face_edges)
void(* finishUVLayer)(const OpenSubdiv_Converter *converter)
void(* getEdgeFaces)(const OpenSubdiv_Converter *converter, const int edge, int *edge_faces)
blender::opensubdiv::EvalOutputAPI * eval_output
blender::BitVector is_loose_bits
ForeachTopologyInformationCb topology_info
ForeachVertexOfLooseEdgeCb vertex_of_loose_edge
ForeachVertexFromCornerCb vertex_every_corner
OpenSubdiv_Evaluator * evaluator
i
Definition text_draw.cc:230