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