Blender V4.5
multires_reshape_util.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#include "DNA_meshdata_types.h"
15#include "DNA_modifier_types.h"
16#include "DNA_object_types.h"
17
18#include "BLI_math_matrix.h"
19#include "BLI_task.h"
20
21#include "BKE_attribute.hh"
22#include "BKE_customdata.hh"
23#include "BKE_mesh_runtime.hh"
24#include "BKE_multires.hh"
25#include "BKE_subdiv.hh"
26#include "BKE_subdiv_ccg.hh"
27#include "BKE_subdiv_eval.hh"
28
30
31/* -------------------------------------------------------------------- */
34
36 /*const*/ Object *object,
37 const MultiresModifierData *mmd)
38{
39 using namespace blender::bke;
40 Mesh *base_mesh;
41
42 if (depsgraph != nullptr) {
44 Object *object_eval = DEG_get_evaluated(depsgraph, object);
45 base_mesh = mesh_get_eval_deform(depsgraph, scene_eval, object_eval, &CD_MASK_BAREMESH);
46 }
47 else {
48 base_mesh = (Mesh *)object->data;
49 }
50
51 subdiv::Settings subdiv_settings;
52 BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
53 subdiv::Subdiv *subdiv = subdiv::new_from_mesh(&subdiv_settings, base_mesh);
54 if (!subdiv) {
55 return nullptr;
56 }
58 subdiv, base_mesh, {}, subdiv::SUBDIV_EVALUATOR_TYPE_CPU, nullptr))
59 {
61 return nullptr;
62 }
63 return subdiv;
64}
65
66static void context_zero(MultiresReshapeContext *reshape_context)
67{
68 *reshape_context = {};
69}
70
71static void context_init_lookup(MultiresReshapeContext *reshape_context)
72{
73 const blender::OffsetIndices faces = reshape_context->base_faces;
74
75 reshape_context->face_start_grid_index = MEM_malloc_arrayN<int>(size_t(faces.size()),
76 "face_start_grid_index");
77 int num_grids = 0;
78 int num_ptex_faces = 0;
79 for (const int face_index : faces.index_range()) {
80 const int num_corners = faces[face_index].size();
81 reshape_context->face_start_grid_index[face_index] = num_grids;
82 num_grids += num_corners;
83 num_ptex_faces += (num_corners == 4) ? 1 : num_corners;
84 }
85
86 reshape_context->grid_to_face_index = MEM_malloc_arrayN<int>(size_t(num_grids),
87 "grid_to_face_index");
88 reshape_context->ptex_start_grid_index = MEM_malloc_arrayN<int>(size_t(num_ptex_faces),
89 "ptex_start_grid_index");
90 for (int face_index = 0, grid_index = 0, ptex_index = 0; face_index < faces.size(); ++face_index)
91 {
92 const int num_corners = faces[face_index].size();
93 const int num_face_ptex_faces = (num_corners == 4) ? 1 : num_corners;
94 for (int i = 0; i < num_face_ptex_faces; ++i) {
95 reshape_context->ptex_start_grid_index[ptex_index + i] = grid_index + i;
96 }
97 for (int corner = 0; corner < num_corners; ++corner, ++grid_index) {
98 reshape_context->grid_to_face_index[grid_index] = face_index;
99 }
100 ptex_index += num_face_ptex_faces;
101 }
102
103 /* Store number of grids, which will be used for sanity checks. */
104 reshape_context->num_grids = num_grids;
105}
106
108{
109 Mesh *base_mesh = reshape_context->base_mesh;
110 reshape_context->mdisps = static_cast<MDisps *>(
112 reshape_context->grid_paint_masks = static_cast<GridPaintMask *>(CustomData_get_layer_for_write(
113 &base_mesh->corner_data, CD_GRID_PAINT_MASK, base_mesh->corners_num));
114}
115
116static void context_init_common(MultiresReshapeContext *reshape_context)
117{
118 BLI_assert(reshape_context->subdiv != nullptr);
119 BLI_assert(reshape_context->base_mesh != nullptr);
120
122 reshape_context->subdiv);
123
124 context_init_lookup(reshape_context);
125 context_init_grid_pointers(reshape_context);
126}
127
128static bool context_is_valid(MultiresReshapeContext *reshape_context)
129{
130 if (reshape_context->mdisps == nullptr) {
131 /* Multi-resolution displacement has been removed before current changes were applies. */
132 return false;
133 }
134 return true;
135}
136
138{
139 const bool is_valid = context_is_valid(reshape_context);
140 if (!is_valid) {
141 multires_reshape_context_free(reshape_context);
142 }
143 return is_valid;
144}
145
147 Depsgraph *depsgraph,
148 Object *object,
150{
151 context_zero(reshape_context);
152
153 const bool use_render_params = false;
155 Mesh *base_mesh = (Mesh *)object->data;
156
157 reshape_context->depsgraph = depsgraph;
158 reshape_context->object = object;
159 reshape_context->mmd = mmd;
160
161 reshape_context->base_mesh = base_mesh;
162 reshape_context->base_positions = base_mesh->vert_positions();
163 reshape_context->base_edges = base_mesh->edges();
164 reshape_context->base_faces = base_mesh->faces();
165 reshape_context->base_corner_verts = base_mesh->corner_verts();
166 reshape_context->base_corner_edges = base_mesh->corner_edges();
167
168 reshape_context->subdiv = multires_reshape_create_subdiv(nullptr, object, mmd);
169 if (!reshape_context->subdiv) {
170 return false;
171 }
172 reshape_context->need_free_subdiv = true;
173
174 reshape_context->reshape.level = multires_get_level(
175 scene_eval, object, mmd, use_render_params, true);
177 reshape_context->reshape.level);
178
179 reshape_context->top.level = mmd->totlvl;
181 reshape_context->top.level);
182
183 context_init_common(reshape_context);
184
185 return context_verify_or_free(reshape_context);
186}
187
189 Depsgraph *depsgraph,
190 Object *object,
192{
193 using namespace blender;
194 using namespace blender::bke;
195 context_zero(reshape_context);
196
197 const bool use_render_params = false;
199 Mesh *base_mesh = (Mesh *)object->data;
200
201 reshape_context->depsgraph = depsgraph;
202 reshape_context->object = object;
203 reshape_context->mmd = mmd;
204
205 reshape_context->base_mesh = base_mesh;
206 reshape_context->base_positions = base_mesh->vert_positions();
207 reshape_context->base_edges = base_mesh->edges();
208 reshape_context->base_faces = base_mesh->faces();
209 reshape_context->base_corner_verts = base_mesh->corner_verts();
210 reshape_context->base_corner_edges = base_mesh->corner_edges();
211
212 reshape_context->subdiv = multires_reshape_create_subdiv(depsgraph, object, mmd);
213 if (!reshape_context->subdiv) {
214 return false;
215 }
216 reshape_context->need_free_subdiv = true;
217
218 reshape_context->reshape.level = multires_get_level(
219 scene_eval, object, mmd, use_render_params, true);
221 reshape_context->reshape.level);
222
223 reshape_context->top.level = mmd->totlvl;
224 reshape_context->top.grid_size = subdiv::grid_size_from_level(reshape_context->top.level);
225
226 const bke::AttributeAccessor attributes = base_mesh->attributes();
227 reshape_context->cd_vertex_crease = *attributes.lookup<float>("crease_vert", AttrDomain::Point);
228 reshape_context->cd_edge_crease = *attributes.lookup<float>("crease_edge", AttrDomain::Edge);
229
230 context_init_common(reshape_context);
231
232 return context_verify_or_free(reshape_context);
233}
234
236 SubdivCCG *subdiv_ccg,
237 Mesh *base_mesh,
238 int top_level)
239{
240 context_zero(reshape_context);
241
242 reshape_context->base_mesh = base_mesh;
243 reshape_context->base_positions = base_mesh->vert_positions();
244 reshape_context->base_edges = base_mesh->edges();
245 reshape_context->base_faces = base_mesh->faces();
246 reshape_context->base_corner_verts = base_mesh->corner_verts();
247 reshape_context->base_corner_edges = base_mesh->corner_edges();
248
249 reshape_context->subdiv = subdiv_ccg->subdiv;
250 reshape_context->need_free_subdiv = false;
251
252 reshape_context->reshape.level = subdiv_ccg->level;
254 reshape_context->reshape.level);
255
256 reshape_context->top.level = top_level;
258 reshape_context->top.level);
259
260 context_init_common(reshape_context);
261
262 return context_verify_or_free(reshape_context);
263}
264
266 Object *object,
268 int top_level)
269{
271
273 reshape_context, object, mmd, subdiv, top_level);
274
275 reshape_context->need_free_subdiv = true;
276
277 return result;
278}
279
281 Object *object,
284 int top_level)
285{
286 using namespace blender;
287 using namespace blender::bke;
288 context_zero(reshape_context);
289
290 Mesh *base_mesh = (Mesh *)object->data;
291
292 reshape_context->mmd = mmd;
293 reshape_context->base_mesh = base_mesh;
294 reshape_context->base_positions = base_mesh->vert_positions();
295 reshape_context->base_edges = base_mesh->edges();
296 reshape_context->base_faces = base_mesh->faces();
297 reshape_context->base_corner_verts = base_mesh->corner_verts();
298 reshape_context->base_corner_edges = base_mesh->corner_edges();
299
300 const bke::AttributeAccessor attributes = base_mesh->attributes();
301 reshape_context->cd_vertex_crease = *attributes.lookup<float>("crease_vert", AttrDomain::Point);
302
303 reshape_context->subdiv = subdiv;
304 reshape_context->need_free_subdiv = false;
305
306 reshape_context->reshape.level = mmd->totlvl;
308 reshape_context->reshape.level);
309
310 reshape_context->top.level = top_level;
311 reshape_context->top.grid_size = subdiv::grid_size_from_level(reshape_context->top.level);
312
313 context_init_common(reshape_context);
314
315 return context_verify_or_free(reshape_context);
316}
317
319{
320 MDisps *orig_mdisps = reshape_context->orig.mdisps;
321 GridPaintMask *orig_grid_paint_masks = reshape_context->orig.grid_paint_masks;
322
323 if (orig_mdisps == nullptr && orig_grid_paint_masks == nullptr) {
324 return;
325 }
326
327 const int num_grids = reshape_context->num_grids;
328 for (int grid_index = 0; grid_index < num_grids; grid_index++) {
329 if (orig_mdisps != nullptr) {
330 MDisps *orig_grid = &orig_mdisps[grid_index];
331 MEM_SAFE_FREE(orig_grid->disps);
332 }
333 if (orig_grid_paint_masks != nullptr) {
334 GridPaintMask *orig_paint_mask_grid = &orig_grid_paint_masks[grid_index];
335 MEM_SAFE_FREE(orig_paint_mask_grid->data);
336 }
337 }
338
339 MEM_SAFE_FREE(orig_mdisps);
340 MEM_SAFE_FREE(orig_grid_paint_masks);
341
342 reshape_context->orig.mdisps = nullptr;
343 reshape_context->orig.grid_paint_masks = nullptr;
344}
345
347{
348 if (reshape_context->need_free_subdiv) {
349 blender::bke::subdiv::free(reshape_context->subdiv);
350 }
351
353
354 MEM_SAFE_FREE(reshape_context->face_start_grid_index);
355 MEM_SAFE_FREE(reshape_context->ptex_start_grid_index);
356 MEM_SAFE_FREE(reshape_context->grid_to_face_index);
357}
358
360
361/* -------------------------------------------------------------------- */
364
366 int grid_index)
367{
368 BLI_assert(grid_index >= 0);
369 BLI_assert(grid_index < reshape_context->num_grids);
370
371 /* TODO(sergey): Optimization: when SubdivCCG is known we can calculate face index using
372 * SubdivCCG::grid_faces and SubdivCCG::faces, saving memory used by grid_to_face_index. */
373
374 return reshape_context->grid_to_face_index[grid_index];
375}
376
377int multires_reshape_grid_to_corner(const MultiresReshapeContext *reshape_context, int grid_index)
378{
379 BLI_assert(grid_index >= 0);
380 BLI_assert(grid_index < reshape_context->num_grids);
381
382 /* TODO(sergey): Optimization: when SubdivCCG is known we can calculate face index using
383 * SubdivCCG::grid_faces and SubdivCCG::faces, saving memory used by grid_to_face_index. */
384
385 const int face_index = multires_reshape_grid_to_face_index(reshape_context, grid_index);
386 return grid_index - reshape_context->face_start_grid_index[face_index];
387}
388
389bool multires_reshape_is_quad_face(const MultiresReshapeContext *reshape_context, int face_index)
390{
391 return reshape_context->base_faces[face_index].size() == 4;
392}
393
395 int grid_index)
396{
397 const int face_index = multires_reshape_grid_to_face_index(reshape_context, grid_index);
398 const int corner = multires_reshape_grid_to_corner(reshape_context, grid_index);
399 const bool is_quad = multires_reshape_is_quad_face(reshape_context, face_index);
400 return reshape_context->face_ptex_offset[face_index] + (is_quad ? 0 : corner);
401}
402
404 const GridCoord *grid_coord)
405{
406 PTexCoord ptex_coord;
407
408 ptex_coord.ptex_face_index = multires_reshape_grid_to_ptex_index(reshape_context,
409 grid_coord->grid_index);
410
411 float corner_u, corner_v;
413 grid_coord->u, grid_coord->v, &corner_u, &corner_v);
414
415 const int face_index = multires_reshape_grid_to_face_index(reshape_context,
416 grid_coord->grid_index);
417 const int corner = multires_reshape_grid_to_corner(reshape_context, grid_coord->grid_index);
418 if (multires_reshape_is_quad_face(reshape_context, face_index)) {
419 float grid_u, grid_v;
420 blender::bke::subdiv::ptex_face_uv_to_grid_uv(corner_u, corner_v, &grid_u, &grid_v);
422 corner, grid_u, grid_v, &ptex_coord.u, &ptex_coord.v);
423 }
424 else {
425 ptex_coord.u = corner_u;
426 ptex_coord.v = corner_v;
427 }
428
429 return ptex_coord;
430}
431
433 const PTexCoord *ptex_coord)
434{
435 GridCoord grid_coord;
436
437 const int start_grid_index = reshape_context->ptex_start_grid_index[ptex_coord->ptex_face_index];
438 const int face_index = reshape_context->grid_to_face_index[start_grid_index];
439
440 int corner_delta;
441 if (multires_reshape_is_quad_face(reshape_context, face_index)) {
443 ptex_coord->u, ptex_coord->v, &grid_coord.u, &grid_coord.v);
444 }
445 else {
446 corner_delta = 0;
447 grid_coord.u = ptex_coord->u;
448 grid_coord.v = ptex_coord->v;
449 }
450 grid_coord.grid_index = start_grid_index + corner_delta;
451
453 grid_coord.u, grid_coord.v, &grid_coord.u, &grid_coord.v);
454
455 return grid_coord;
456}
457
459 const int face_index,
460 const int corner,
461 const float dPdu[3],
462 const float dPdv[3],
463 float r_tangent_matrix[3][3])
464{
465 /* For a quad faces we would need to flip the tangent, since they will use
466 * use different coordinates within displacement grid compared to the ptex face. */
467 const bool is_quad = multires_reshape_is_quad_face(reshape_context, face_index);
468 const int tangent_corner = is_quad ? corner : 0;
469 BKE_multires_construct_tangent_matrix(r_tangent_matrix, dPdu, dPdv, tangent_corner);
470}
471
473 const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord)
474{
475 ReshapeGridElement grid_element = {nullptr, nullptr};
476
477 const int grid_size = reshape_context->top.grid_size;
478 const int grid_x = lround(grid_coord->u * (grid_size - 1));
479 const int grid_y = lround(grid_coord->v * (grid_size - 1));
480 const int grid_element_index = grid_y * grid_size + grid_x;
481
482 if (reshape_context->mdisps != nullptr) {
483 MDisps *displacement_grid = &reshape_context->mdisps[grid_coord->grid_index];
484 grid_element.displacement = displacement_grid->disps[grid_element_index];
485 }
486
487 if (reshape_context->grid_paint_masks != nullptr) {
488 GridPaintMask *grid_paint_mask = &reshape_context->grid_paint_masks[grid_coord->grid_index];
489 grid_element.mask = &grid_paint_mask->data[grid_element_index];
490 }
491
492 return grid_element;
493}
494
496 const MultiresReshapeContext *reshape_context, const PTexCoord *ptex_coord)
497{
498 GridCoord grid_coord = multires_reshape_ptex_coord_to_grid(reshape_context, ptex_coord);
499 return multires_reshape_grid_element_for_grid_coord(reshape_context, &grid_coord);
500}
501
503 const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord)
504{
505 ReshapeConstGridElement grid_element = {{0.0f, 0.0f, 0.0f}, 0.0f};
506
507 const MDisps *mdisps = reshape_context->orig.mdisps;
508 if (mdisps != nullptr) {
509 const MDisps *displacement_grid = &mdisps[grid_coord->grid_index];
510 if (displacement_grid->disps != nullptr) {
511 const int grid_size = blender::bke::subdiv::grid_size_from_level(displacement_grid->level);
512 const int grid_x = lround(grid_coord->u * (grid_size - 1));
513 const int grid_y = lround(grid_coord->v * (grid_size - 1));
514 const int grid_element_index = grid_y * grid_size + grid_x;
515 copy_v3_v3(grid_element.displacement, displacement_grid->disps[grid_element_index]);
516 }
517 }
518
519 const GridPaintMask *grid_paint_masks = reshape_context->orig.grid_paint_masks;
520 if (grid_paint_masks != nullptr) {
521 const GridPaintMask *paint_mask_grid = &grid_paint_masks[grid_coord->grid_index];
522 if (paint_mask_grid->data != nullptr) {
523 const int grid_size = blender::bke::subdiv::grid_size_from_level(paint_mask_grid->level);
524 const int grid_x = lround(grid_coord->u * (grid_size - 1));
525 const int grid_y = lround(grid_coord->v * (grid_size - 1));
526 const int grid_element_index = grid_y * grid_size + grid_x;
527 grid_element.mask = paint_mask_grid->data[grid_element_index];
528 }
529 }
530
531 return grid_element;
532}
533
535
536/* -------------------------------------------------------------------- */
539
541 const GridCoord *grid_coord,
542 float r_P[3],
543 float r_tangent_matrix[3][3])
544{
545 float dPdu[3], dPdv[3];
546 const PTexCoord ptex_coord = multires_reshape_grid_coord_to_ptex(reshape_context, grid_coord);
547 blender::bke::subdiv::Subdiv *subdiv = reshape_context->subdiv;
549 subdiv, ptex_coord.ptex_face_index, ptex_coord.u, ptex_coord.v, r_P, dPdu, dPdv);
550
551 const int face_index = multires_reshape_grid_to_face_index(reshape_context,
552 grid_coord->grid_index);
553 const int corner = multires_reshape_grid_to_corner(reshape_context, grid_coord->grid_index);
555 reshape_context, face_index, corner, dPdu, dPdv, r_tangent_matrix);
556}
557
559
560/* -------------------------------------------------------------------- */
563
564static void allocate_displacement_grid(MDisps *displacement_grid, const int level)
565{
566 const int grid_size = blender::bke::subdiv::grid_size_from_level(level);
567 const int grid_area = grid_size * grid_size;
568 float(*disps)[3] = MEM_calloc_arrayN<float[3]>(grid_area, "multires disps");
569 if (displacement_grid->disps != nullptr) {
570 MEM_freeN(displacement_grid->disps);
571 }
572 /* TODO(sergey): Preserve data on the old level. */
573 displacement_grid->disps = disps;
574 displacement_grid->totdisp = grid_area;
575 displacement_grid->level = level;
576}
577
578static void ensure_displacement_grid(MDisps *displacement_grid, const int level)
579{
580 if (displacement_grid->disps != nullptr && displacement_grid->level >= level) {
581 return;
582 }
583 allocate_displacement_grid(displacement_grid, level);
584}
585
586static void ensure_displacement_grids(Mesh *mesh, const int grid_level)
587{
588 const int num_grids = mesh->corners_num;
589 MDisps *mdisps = static_cast<MDisps *>(
590 CustomData_get_layer_for_write(&mesh->corner_data, CD_MDISPS, mesh->corners_num));
591 for (int grid_index = 0; grid_index < num_grids; grid_index++) {
592 ensure_displacement_grid(&mdisps[grid_index], grid_level);
593 }
594}
595
596static void ensure_mask_grids(Mesh *mesh, const int level)
597{
598 GridPaintMask *grid_paint_masks = static_cast<GridPaintMask *>(
599 CustomData_get_layer_for_write(&mesh->corner_data, CD_GRID_PAINT_MASK, mesh->corners_num));
600 if (grid_paint_masks == nullptr) {
601 return;
602 }
603 const int num_grids = mesh->corners_num;
604 const int grid_size = blender::bke::subdiv::grid_size_from_level(level);
605 const int grid_area = grid_size * grid_size;
606 for (int grid_index = 0; grid_index < num_grids; grid_index++) {
607 GridPaintMask *grid_paint_mask = &grid_paint_masks[grid_index];
608 if (grid_paint_mask->level >= level) {
609 continue;
610 }
611 grid_paint_mask->level = level;
612 if (grid_paint_mask->data) {
613 MEM_freeN(grid_paint_mask->data);
614 }
615 /* TODO(sergey): Preserve data on the old level. */
616 grid_paint_mask->data = MEM_calloc_arrayN<float>(grid_area, "gpm.data");
617 }
618}
619
621{
623 ensure_mask_grids(mesh, level);
624}
625
627
628/* -------------------------------------------------------------------- */
631
633{
634 const MDisps *mdisps = reshape_context->mdisps;
635 const GridPaintMask *grid_paint_masks = reshape_context->grid_paint_masks;
636
637 MDisps *orig_mdisps = static_cast<MDisps *>(MEM_dupallocN(mdisps));
638 GridPaintMask *orig_grid_paint_masks = nullptr;
639 if (grid_paint_masks != nullptr) {
640 orig_grid_paint_masks = static_cast<GridPaintMask *>(MEM_dupallocN(grid_paint_masks));
641 }
642
643 const int num_grids = reshape_context->num_grids;
644 for (int grid_index = 0; grid_index < num_grids; grid_index++) {
645 MDisps *orig_grid = &orig_mdisps[grid_index];
646 /* Ignore possibly invalid/non-allocated original grids. They will be replaced with 0 original
647 * data when accessed during reshape process.
648 * Reshape process will ensure all grids are on top level, but that happens on separate set of
649 * grids which eventually replaces original one. */
650 if (orig_grid->disps != nullptr) {
651 orig_grid->disps = static_cast<float(*)[3]>(MEM_dupallocN(orig_grid->disps));
652 }
653 if (orig_grid_paint_masks != nullptr) {
654 GridPaintMask *orig_paint_mask_grid = &orig_grid_paint_masks[grid_index];
655 if (orig_paint_mask_grid->data != nullptr) {
656 orig_paint_mask_grid->data = static_cast<float *>(
657 MEM_dupallocN(orig_paint_mask_grid->data));
658 }
659 }
660 }
661
662 reshape_context->orig.mdisps = orig_mdisps;
663 reshape_context->orig.grid_paint_masks = orig_grid_paint_masks;
664}
665
666using ForeachGridCoordinateCallback = void (*)(const MultiresReshapeContext *reshape_context,
667 const GridCoord *grid_coord,
668 void *userdata_v);
669
679
680static void foreach_grid_face_coordinate_task(void *__restrict userdata_v,
681 const int face_index,
682 const TaskParallelTLS *__restrict /*tls*/)
683{
685
686 const MultiresReshapeContext *reshape_context = data->reshape_context;
687
688 const blender::OffsetIndices faces = reshape_context->base_faces;
689 const int grid_size = data->grid_size;
690 const float grid_size_1_inv = 1.0f / (float(grid_size) - 1.0f);
691
692 const int num_corners = faces[face_index].size();
693 int grid_index = reshape_context->face_start_grid_index[face_index];
694 for (int corner = 0; corner < num_corners; ++corner, ++grid_index) {
695 for (int y = 0; y < grid_size; ++y) {
696 const float v = float(y) * grid_size_1_inv;
697 for (int x = 0; x < grid_size; ++x) {
698 const float u = float(x) * grid_size_1_inv;
699
700 GridCoord grid_coord;
701 grid_coord.grid_index = grid_index;
702 grid_coord.u = u;
703 grid_coord.v = v;
704
705 data->callback(data->reshape_context, &grid_coord, data->callback_userdata_v);
706 }
707 }
708 }
709}
710
711/* Run given callback for every grid coordinate at a given level. */
712static void foreach_grid_coordinate(const MultiresReshapeContext *reshape_context,
713 const int level,
715 void *userdata_v)
716{
718 data.reshape_context = reshape_context;
720 data.grid_size_1_inv = 1.0f / (float(data.grid_size) - 1.0f);
721 data.callback = callback;
722 data.callback_userdata_v = userdata_v;
723
724 TaskParallelSettings parallel_range_settings;
725 BLI_parallel_range_settings_defaults(&parallel_range_settings);
726 parallel_range_settings.min_iter_per_thread = 1;
727
728 const Mesh *base_mesh = reshape_context->base_mesh;
729 const int num_faces = base_mesh->faces_num;
731 0, num_faces, &data, foreach_grid_face_coordinate_task, &parallel_range_settings);
732}
733
735 const MultiresReshapeContext *reshape_context,
736 const GridCoord *grid_coord,
737 void * /*userdata_v*/)
738{
739 float P[3];
740 float tangent_matrix[3][3];
741 multires_reshape_evaluate_limit_at_grid(reshape_context, grid_coord, P, tangent_matrix);
742
743 float inv_tangent_matrix[3][3];
744 invert_m3_m3(inv_tangent_matrix, tangent_matrix);
745
747 grid_coord);
748
749 float D[3];
750 sub_v3_v3v3(D, grid_element.displacement, P);
751
752 float tangent_D[3];
753 mul_v3_m3v3(tangent_D, inv_tangent_matrix, D);
754
755 copy_v3_v3(grid_element.displacement, tangent_D);
756}
757
759 const MultiresReshapeContext *reshape_context)
760{
761 foreach_grid_coordinate(reshape_context,
762 reshape_context->top.level,
764 nullptr);
765}
766
768
769/* -------------------------------------------------------------------- */
772
773/* TODO(sergey): Make foreach_grid_coordinate more accessible and move this functionality to
774 * its own file. */
775
777 const GridCoord *grid_coord,
778 void * /*userdata_v*/)
779{
780 float P[3];
781 float tangent_matrix[3][3];
782 multires_reshape_evaluate_limit_at_grid(reshape_context, grid_coord, P, tangent_matrix);
783
785 grid_coord);
786 float D[3];
787 mul_v3_m3v3(D, tangent_matrix, grid_element.displacement);
788
789 add_v3_v3v3(grid_element.displacement, P, D);
790}
791
793 const MultiresReshapeContext *reshape_context)
794{
796 reshape_context, reshape_context->top.level, assign_final_coords_from_mdisps, nullptr);
797}
798
800 const GridCoord *grid_coord,
801 void * /*userdata_v*/)
802{
803 float P[3];
804 float tangent_matrix[3][3];
805 multires_reshape_evaluate_limit_at_grid(reshape_context, grid_coord, P, tangent_matrix);
806
807 const ReshapeConstGridElement orig_grid_element =
808 multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord);
809
810 float D[3];
811 mul_v3_m3v3(D, tangent_matrix, orig_grid_element.displacement);
812
814 grid_coord);
815 add_v3_v3v3(grid_element.displacement, P, D);
816
817 if (grid_element.mask != nullptr) {
818 *grid_element.mask = orig_grid_element.mask;
819 }
820}
821
823 const MultiresReshapeContext *reshape_context)
824{
825 foreach_grid_coordinate(reshape_context,
826 reshape_context->top.level,
828 nullptr);
829}
830
CustomData interface, see also DNA_customdata_types.h.
const CustomData_MeshMasks CD_MASK_BAREMESH
void * CustomData_get_layer_for_write(CustomData *data, eCustomDataType type, int totelem)
void BKE_multires_subdiv_settings_init(blender::bke::subdiv::Settings *settings, const MultiresModifierData *mmd)
BLI_INLINE void BKE_multires_construct_tangent_matrix(float tangent_matrix[3][3], const float dPdu[3], const float dPdv[3], int corner)
int multires_get_level(const Scene *scene, const Object *ob, const MultiresModifierData *mmd, bool render, bool ignore_simplify)
Definition multires.cc:323
#define D
#define BLI_assert(a)
Definition BLI_assert.h:46
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])
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition task_range.cc:99
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:221
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ CD_GRID_PAINT_MASK
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v
BPy_StructRNA * depsgraph
AttributeSet attributes
GAttributeReader lookup(const StringRef attribute_id) const
#define MEM_SAFE_FREE(v)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static char faces[256]
int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_context, int grid_index)
void multires_reshape_assign_final_elements_from_orig_mdisps(const MultiresReshapeContext *reshape_context)
static void ensure_displacement_grids(Mesh *mesh, const int grid_level)
bool multires_reshape_is_quad_face(const MultiresReshapeContext *reshape_context, int face_index)
void multires_reshape_assign_final_coords_from_mdisps(const MultiresReshapeContext *reshape_context)
static void context_init_grid_pointers(MultiresReshapeContext *reshape_context)
bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape_context, Depsgraph *depsgraph, Object *object, MultiresModifierData *mmd)
static void object_grid_element_to_tangent_displacement(const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord, void *)
bool multires_reshape_context_create_from_subdiv(MultiresReshapeContext *reshape_context, Object *object, MultiresModifierData *mmd, blender::bke::subdiv::Subdiv *subdiv, int top_level)
static bool context_verify_or_free(MultiresReshapeContext *reshape_context)
ReshapeGridElement multires_reshape_grid_element_for_grid_coord(const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord)
int multires_reshape_grid_to_ptex_index(const MultiresReshapeContext *reshape_context, int grid_index)
static void context_init_lookup(MultiresReshapeContext *reshape_context)
PTexCoord multires_reshape_grid_coord_to_ptex(const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord)
void multires_reshape_context_free(MultiresReshapeContext *reshape_context)
void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_context)
static void assign_final_coords_from_mdisps(const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord, void *)
static void assign_final_elements_from_orig_mdisps(const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord, void *)
static void allocate_displacement_grid(MDisps *displacement_grid, const int level)
static void context_init_common(MultiresReshapeContext *reshape_context)
int multires_reshape_grid_to_corner(const MultiresReshapeContext *reshape_context, int grid_index)
void multires_reshape_tangent_matrix_for_corner(const MultiresReshapeContext *reshape_context, const int face_index, const int corner, const float dPdu[3], const float dPdv[3], float r_tangent_matrix[3][3])
static void foreach_grid_face_coordinate_task(void *__restrict userdata_v, const int face_index, const TaskParallelTLS *__restrict)
void multires_reshape_ensure_grids(Mesh *mesh, const int level)
void multires_reshape_free_original_grids(MultiresReshapeContext *reshape_context)
static void foreach_grid_coordinate(const MultiresReshapeContext *reshape_context, const int level, ForeachGridCoordinateCallback callback, void *userdata_v)
blender::bke::subdiv::Subdiv * multires_reshape_create_subdiv(Depsgraph *depsgraph, Object *object, const MultiresModifierData *mmd)
static void context_zero(MultiresReshapeContext *reshape_context)
bool multires_reshape_context_create_from_modifier(MultiresReshapeContext *reshape_context, Object *object, MultiresModifierData *mmd, int top_level)
void multires_reshape_object_grids_to_tangent_displacement(const MultiresReshapeContext *reshape_context)
void(*)(const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord, void *userdata_v) ForeachGridCoordinateCallback
bool multires_reshape_context_create_from_base_mesh(MultiresReshapeContext *reshape_context, Depsgraph *depsgraph, Object *object, MultiresModifierData *mmd)
ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord(const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord)
ReshapeGridElement multires_reshape_grid_element_for_ptex_coord(const MultiresReshapeContext *reshape_context, const PTexCoord *ptex_coord)
static void ensure_displacement_grid(MDisps *displacement_grid, const int level)
static bool context_is_valid(MultiresReshapeContext *reshape_context)
GridCoord multires_reshape_ptex_coord_to_grid(const MultiresReshapeContext *reshape_context, const PTexCoord *ptex_coord)
static void ensure_mask_grids(Mesh *mesh, const int level)
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])
bool multires_reshape_context_create_from_ccg(MultiresReshapeContext *reshape_context, SubdivCCG *subdiv_ccg, Mesh *base_mesh, int top_level)
void free(Subdiv *subdiv)
Definition subdiv.cc:190
BLI_INLINE void rotate_grid_to_quad(int corner, float grid_u, float grid_v, float *r_quad_u, float *r_quad_v)
bool eval_begin_from_mesh(Subdiv *subdiv, const Mesh *mesh, Span< float3 > coarse_vert_positions, eSubdivEvaluatorType evaluator_type, OpenSubdiv_EvaluatorCache *evaluator_cache)
Subdiv * new_from_mesh(const Settings *settings, const Mesh *mesh)
Definition subdiv.cc:131
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])
BLI_INLINE void grid_uv_to_ptex_face_uv(float grid_u, float grid_v, float *r_ptex_u, float *r_ptex_v)
BLI_INLINE void ptex_face_uv_to_grid_uv(float ptex_u, float ptex_v, float *r_grid_u, float *r_grid_v)
BLI_INLINE int grid_size_from_level(int level)
BLI_INLINE int rotate_quad_to_corner(float quad_u, float quad_v, float *r_corner_u, float *r_corner_v)
int * face_ptex_offset_get(Subdiv *subdiv)
Definition subdiv.cc:217
Mesh * mesh_get_eval_deform(Depsgraph *depsgraph, const Scene *scene, Object *ob, const CustomData_MeshMasks *dataMask)
ForeachGridCoordinateCallback callback
const MultiresReshapeContext * reshape_context
float(* disps)[3]
int corners_num
CustomData corner_data
int faces_num
struct MultiresReshapeContext::@217025040031013155267033302301341011136345264200 reshape
blender::bke::subdiv::Subdiv * subdiv
blender::VArraySpan< float > cd_vertex_crease
blender::Span< int > base_corner_edges
GridPaintMask * grid_paint_masks
blender::VArraySpan< float > cd_edge_crease
blender::OffsetIndices< int > base_faces
blender::Span< blender::int2 > base_edges
blender::Span< blender::float3 > base_positions
blender::Span< int > base_corner_verts
MultiresModifierData * mmd
struct MultiresReshapeContext::@240345071146130371125365207064366216255363142356 orig
struct MultiresReshapeContext::@020251072072313275303356043045365232052345353114 top
blender::bke::subdiv::Subdiv * subdiv
i
Definition text_draw.cc:230