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