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
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
31
32#include "atomic_ops.h"
33#include "subdiv_converter.hh"
34
35#ifdef WITH_OPENSUBDIV
36
37/* -------------------------------------------------------------------- */
40
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
166
167/* -------------------------------------------------------------------- */
170
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
245
246/* -------------------------------------------------------------------- */
249
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
310
311/* -------------------------------------------------------------------- */
314
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
434
435/* -------------------------------------------------------------------- */
441
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
868
869/* -------------------------------------------------------------------- */
872
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
1181
1182/* -------------------------------------------------------------------- */
1185
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
1303
1304/* -------------------------------------------------------------------- */
1307
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
1322
1323/* -------------------------------------------------------------------- */
1326
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
1430
1431/* -------------------------------------------------------------------- */
1434
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 D
#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)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
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
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)
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:95
OpenSubdiv_FVarLinearInterpolation
OpenSubdiv_VtxBoundaryInterpolation
OpenSubdiv_SchemeType
@ OSD_SCHEME_CATMARK
int edges_num
struct MultiresReshapeContext::@200156053054134230066312172364357207125266140353 top
blender::bke::subdiv::Subdiv * subdiv
blender::VArraySpan< float > cd_vertex_crease
blender::OffsetIndices< int > base_faces
struct MultiresReshapeContext::@354360336041134252127126015345003241176221362327 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