Blender V4.3
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
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/* -------------------------------------------------------------------- */
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_object(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 }
57 if (!subdiv::eval_begin_from_mesh(
58 subdiv, base_mesh, {}, subdiv::SUBDIV_EVALUATOR_TYPE_CPU, nullptr))
59 {
60 subdiv::free(subdiv);
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 Mesh *base_mesh = reshape_context->base_mesh;
74 const blender::OffsetIndices faces = reshape_context->base_faces;
75 const int num_faces = base_mesh->faces_num;
76
77 reshape_context->face_start_grid_index = static_cast<int *>(
78 MEM_malloc_arrayN(num_faces, sizeof(int), "face_start_grid_index"));
79 int num_grids = 0;
80 int num_ptex_faces = 0;
81 for (int face_index = 0; face_index < num_faces; ++face_index) {
82 const int num_corners = faces[face_index].size();
83 reshape_context->face_start_grid_index[face_index] = num_grids;
84 num_grids += num_corners;
85 num_ptex_faces += (num_corners == 4) ? 1 : num_corners;
86 }
87
88 reshape_context->grid_to_face_index = static_cast<int *>(
89 MEM_malloc_arrayN(num_grids, sizeof(int), "grid_to_face_index"));
90 reshape_context->ptex_start_grid_index = static_cast<int *>(
91 MEM_malloc_arrayN(num_ptex_faces, sizeof(int), "ptex_start_grid_index"));
92 for (int face_index = 0, grid_index = 0, ptex_index = 0; face_index < num_faces; ++face_index) {
93 const int num_corners = faces[face_index].size();
94 const int num_face_ptex_faces = (num_corners == 4) ? 1 : num_corners;
95 for (int i = 0; i < num_face_ptex_faces; ++i) {
96 reshape_context->ptex_start_grid_index[ptex_index + i] = grid_index + i;
97 }
98 for (int corner = 0; corner < num_corners; ++corner, ++grid_index) {
99 reshape_context->grid_to_face_index[grid_index] = face_index;
100 }
101 ptex_index += num_face_ptex_faces;
102 }
103
104 /* Store number of grids, which will be used for sanity checks. */
105 reshape_context->num_grids = num_grids;
106}
107
109{
110 Mesh *base_mesh = reshape_context->base_mesh;
111 reshape_context->mdisps = static_cast<MDisps *>(
113 reshape_context->grid_paint_masks = static_cast<GridPaintMask *>(CustomData_get_layer_for_write(
114 &base_mesh->corner_data, CD_GRID_PAINT_MASK, base_mesh->corners_num));
115}
116
117static void context_init_common(MultiresReshapeContext *reshape_context)
118{
119 BLI_assert(reshape_context->subdiv != nullptr);
120 BLI_assert(reshape_context->base_mesh != nullptr);
121
123 reshape_context->subdiv);
124
125 context_init_lookup(reshape_context);
126 context_init_grid_pointers(reshape_context);
127}
128
129static bool context_is_valid(MultiresReshapeContext *reshape_context)
130{
131 if (reshape_context->mdisps == nullptr) {
132 /* Multi-resolution displacement has been removed before current changes were applies. */
133 return false;
134 }
135 return true;
136}
137
139{
140 const bool is_valid = context_is_valid(reshape_context);
141 if (!is_valid) {
142 multires_reshape_context_free(reshape_context);
143 }
144 return is_valid;
145}
146
148 Depsgraph *depsgraph,
149 Object *object,
151{
152 context_zero(reshape_context);
153
154 const bool use_render_params = false;
156 Mesh *base_mesh = (Mesh *)object->data;
157
158 reshape_context->depsgraph = depsgraph;
159 reshape_context->object = object;
160 reshape_context->mmd = mmd;
161
162 reshape_context->base_mesh = base_mesh;
163 reshape_context->base_positions = base_mesh->vert_positions();
164 reshape_context->base_edges = base_mesh->edges();
165 reshape_context->base_faces = base_mesh->faces();
166 reshape_context->base_corner_verts = base_mesh->corner_verts();
167 reshape_context->base_corner_edges = base_mesh->corner_edges();
168
169 reshape_context->subdiv = multires_reshape_create_subdiv(nullptr, object, mmd);
170 if (!reshape_context->subdiv) {
171 return false;
172 }
173 reshape_context->need_free_subdiv = true;
174
175 reshape_context->reshape.level = multires_get_level(
176 scene_eval, object, mmd, use_render_params, true);
178 reshape_context->reshape.level);
179
180 reshape_context->top.level = mmd->totlvl;
182 reshape_context->top.level);
183
184 context_init_common(reshape_context);
185
186 return context_verify_or_free(reshape_context);
187}
188
190 Depsgraph *depsgraph,
191 Object *object,
193{
194 using namespace blender;
195 using namespace blender::bke;
196 context_zero(reshape_context);
197
198 const bool use_render_params = false;
200 Mesh *base_mesh = (Mesh *)object->data;
201
202 reshape_context->depsgraph = depsgraph;
203 reshape_context->object = object;
204 reshape_context->mmd = mmd;
205
206 reshape_context->base_mesh = base_mesh;
207 reshape_context->base_positions = base_mesh->vert_positions();
208 reshape_context->base_edges = base_mesh->edges();
209 reshape_context->base_faces = base_mesh->faces();
210 reshape_context->base_corner_verts = base_mesh->corner_verts();
211 reshape_context->base_corner_edges = base_mesh->corner_edges();
212
213 reshape_context->subdiv = multires_reshape_create_subdiv(depsgraph, object, mmd);
214 if (!reshape_context->subdiv) {
215 return false;
216 }
217 reshape_context->need_free_subdiv = true;
218
219 reshape_context->reshape.level = multires_get_level(
220 scene_eval, object, mmd, use_render_params, true);
221 reshape_context->reshape.grid_size = subdiv::grid_size_from_level(
222 reshape_context->reshape.level);
223
224 reshape_context->top.level = mmd->totlvl;
225 reshape_context->top.grid_size = subdiv::grid_size_from_level(reshape_context->top.level);
226
227 const bke::AttributeAccessor attributes = base_mesh->attributes();
228 reshape_context->cd_vertex_crease = *attributes.lookup<float>("crease_vert", AttrDomain::Point);
229 reshape_context->cd_edge_crease = *attributes.lookup<float>("crease_edge", AttrDomain::Edge);
230
231 context_init_common(reshape_context);
232
233 return context_verify_or_free(reshape_context);
234}
235
237 SubdivCCG *subdiv_ccg,
238 Mesh *base_mesh,
239 int top_level)
240{
241 context_zero(reshape_context);
242
243 reshape_context->base_mesh = base_mesh;
244 reshape_context->base_positions = base_mesh->vert_positions();
245 reshape_context->base_edges = base_mesh->edges();
246 reshape_context->base_faces = base_mesh->faces();
247 reshape_context->base_corner_verts = base_mesh->corner_verts();
248 reshape_context->base_corner_edges = base_mesh->corner_edges();
249
250 reshape_context->subdiv = subdiv_ccg->subdiv;
251 reshape_context->need_free_subdiv = false;
252
253 reshape_context->reshape.level = subdiv_ccg->level;
255 reshape_context->reshape.level);
256
257 reshape_context->top.level = top_level;
259 reshape_context->top.level);
260
261 context_init_common(reshape_context);
262
263 return context_verify_or_free(reshape_context);
264}
265
267 Object *object,
269 int top_level)
270{
271 blender::bke::subdiv::Subdiv *subdiv = multires_reshape_create_subdiv(nullptr, object, mmd);
272
274 reshape_context, object, mmd, subdiv, top_level);
275
276 reshape_context->need_free_subdiv = true;
277
278 return result;
279}
280
282 Object *object,
285 int top_level)
286{
287 using namespace blender;
288 using namespace blender::bke;
289 context_zero(reshape_context);
290
291 Mesh *base_mesh = (Mesh *)object->data;
292
293 reshape_context->mmd = mmd;
294 reshape_context->base_mesh = base_mesh;
295 reshape_context->base_positions = base_mesh->vert_positions();
296 reshape_context->base_edges = base_mesh->edges();
297 reshape_context->base_faces = base_mesh->faces();
298 reshape_context->base_corner_verts = base_mesh->corner_verts();
299 reshape_context->base_corner_edges = base_mesh->corner_edges();
300
301 const bke::AttributeAccessor attributes = base_mesh->attributes();
302 reshape_context->cd_vertex_crease = *attributes.lookup<float>("crease_vert", AttrDomain::Point);
303
304 reshape_context->subdiv = subdiv;
305 reshape_context->need_free_subdiv = false;
306
307 reshape_context->reshape.level = mmd->totlvl;
308 reshape_context->reshape.grid_size = subdiv::grid_size_from_level(
309 reshape_context->reshape.level);
310
311 reshape_context->top.level = top_level;
312 reshape_context->top.grid_size = subdiv::grid_size_from_level(reshape_context->top.level);
313
314 context_init_common(reshape_context);
315
316 return context_verify_or_free(reshape_context);
317}
318
320{
321 MDisps *orig_mdisps = reshape_context->orig.mdisps;
322 GridPaintMask *orig_grid_paint_masks = reshape_context->orig.grid_paint_masks;
323
324 if (orig_mdisps == nullptr && orig_grid_paint_masks == nullptr) {
325 return;
326 }
327
328 const int num_grids = reshape_context->num_grids;
329 for (int grid_index = 0; grid_index < num_grids; grid_index++) {
330 if (orig_mdisps != nullptr) {
331 MDisps *orig_grid = &orig_mdisps[grid_index];
332 MEM_SAFE_FREE(orig_grid->disps);
333 }
334 if (orig_grid_paint_masks != nullptr) {
335 GridPaintMask *orig_paint_mask_grid = &orig_grid_paint_masks[grid_index];
336 MEM_SAFE_FREE(orig_paint_mask_grid->data);
337 }
338 }
339
340 MEM_SAFE_FREE(orig_mdisps);
341 MEM_SAFE_FREE(orig_grid_paint_masks);
342
343 reshape_context->orig.mdisps = nullptr;
344 reshape_context->orig.grid_paint_masks = nullptr;
345}
346
348{
349 if (reshape_context->need_free_subdiv) {
350 blender::bke::subdiv::free(reshape_context->subdiv);
351 }
352
354
355 MEM_SAFE_FREE(reshape_context->face_start_grid_index);
356 MEM_SAFE_FREE(reshape_context->ptex_start_grid_index);
357 MEM_SAFE_FREE(reshape_context->grid_to_face_index);
358}
359
362/* -------------------------------------------------------------------- */
367 int grid_index)
368{
369 BLI_assert(grid_index >= 0);
370 BLI_assert(grid_index < reshape_context->num_grids);
371
372 /* TODO(sergey): Optimization: when SubdivCCG is known we can calculate face index using
373 * SubdivCCG::grid_faces and SubdivCCG::faces, saving memory used by grid_to_face_index. */
374
375 return reshape_context->grid_to_face_index[grid_index];
376}
377
378int multires_reshape_grid_to_corner(const MultiresReshapeContext *reshape_context, int grid_index)
379{
380 BLI_assert(grid_index >= 0);
381 BLI_assert(grid_index < reshape_context->num_grids);
382
383 /* TODO(sergey): Optimization: when SubdivCCG is known we can calculate face index using
384 * SubdivCCG::grid_faces and SubdivCCG::faces, saving memory used by grid_to_face_index. */
385
386 const int face_index = multires_reshape_grid_to_face_index(reshape_context, grid_index);
387 return grid_index - reshape_context->face_start_grid_index[face_index];
388}
389
390bool multires_reshape_is_quad_face(const MultiresReshapeContext *reshape_context, int face_index)
391{
392 return reshape_context->base_faces[face_index].size() == 4;
393}
394
396 int grid_index)
397{
398 const int face_index = multires_reshape_grid_to_face_index(reshape_context, grid_index);
399 const int corner = multires_reshape_grid_to_corner(reshape_context, grid_index);
400 const bool is_quad = multires_reshape_is_quad_face(reshape_context, face_index);
401 return reshape_context->face_ptex_offset[face_index] + (is_quad ? 0 : corner);
402}
403
405 const GridCoord *grid_coord)
406{
407 PTexCoord ptex_coord;
408
409 ptex_coord.ptex_face_index = multires_reshape_grid_to_ptex_index(reshape_context,
410 grid_coord->grid_index);
411
412 float corner_u, corner_v;
414 grid_coord->u, grid_coord->v, &corner_u, &corner_v);
415
416 const int face_index = multires_reshape_grid_to_face_index(reshape_context,
417 grid_coord->grid_index);
418 const int corner = multires_reshape_grid_to_corner(reshape_context, grid_coord->grid_index);
419 if (multires_reshape_is_quad_face(reshape_context, face_index)) {
420 float grid_u, grid_v;
421 blender::bke::subdiv::ptex_face_uv_to_grid_uv(corner_u, corner_v, &grid_u, &grid_v);
423 corner, grid_u, grid_v, &ptex_coord.u, &ptex_coord.v);
424 }
425 else {
426 ptex_coord.u = corner_u;
427 ptex_coord.v = corner_v;
428 }
429
430 return ptex_coord;
431}
432
434 const PTexCoord *ptex_coord)
435{
436 GridCoord grid_coord;
437
438 const int start_grid_index = reshape_context->ptex_start_grid_index[ptex_coord->ptex_face_index];
439 const int face_index = reshape_context->grid_to_face_index[start_grid_index];
440
441 int corner_delta;
442 if (multires_reshape_is_quad_face(reshape_context, face_index)) {
444 ptex_coord->u, ptex_coord->v, &grid_coord.u, &grid_coord.v);
445 }
446 else {
447 corner_delta = 0;
448 grid_coord.u = ptex_coord->u;
449 grid_coord.v = ptex_coord->v;
450 }
451 grid_coord.grid_index = start_grid_index + corner_delta;
452
454 grid_coord.u, grid_coord.v, &grid_coord.u, &grid_coord.v);
455
456 return grid_coord;
457}
458
460 const int face_index,
461 const int corner,
462 const float dPdu[3],
463 const float dPdv[3],
464 float r_tangent_matrix[3][3])
465{
466 /* For a quad faces we would need to flip the tangent, since they will use
467 * use different coordinates within displacement grid compared to the ptex face. */
468 const bool is_quad = multires_reshape_is_quad_face(reshape_context, face_index);
469 const int tangent_corner = is_quad ? corner : 0;
470 BKE_multires_construct_tangent_matrix(r_tangent_matrix, dPdu, dPdv, tangent_corner);
471}
472
474 const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord)
475{
476 ReshapeGridElement grid_element = {nullptr, nullptr};
477
478 const int grid_size = reshape_context->top.grid_size;
479 const int grid_x = lround(grid_coord->u * (grid_size - 1));
480 const int grid_y = lround(grid_coord->v * (grid_size - 1));
481 const int grid_element_index = grid_y * grid_size + grid_x;
482
483 if (reshape_context->mdisps != nullptr) {
484 MDisps *displacement_grid = &reshape_context->mdisps[grid_coord->grid_index];
485 grid_element.displacement = displacement_grid->disps[grid_element_index];
486 }
487
488 if (reshape_context->grid_paint_masks != nullptr) {
489 GridPaintMask *grid_paint_mask = &reshape_context->grid_paint_masks[grid_coord->grid_index];
490 grid_element.mask = &grid_paint_mask->data[grid_element_index];
491 }
492
493 return grid_element;
494}
495
497 const MultiresReshapeContext *reshape_context, const PTexCoord *ptex_coord)
498{
499 GridCoord grid_coord = multires_reshape_ptex_coord_to_grid(reshape_context, ptex_coord);
500 return multires_reshape_grid_element_for_grid_coord(reshape_context, &grid_coord);
501}
502
504 const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord)
505{
506 ReshapeConstGridElement grid_element = {{0.0f, 0.0f, 0.0f}, 0.0f};
507
508 const MDisps *mdisps = reshape_context->orig.mdisps;
509 if (mdisps != nullptr) {
510 const MDisps *displacement_grid = &mdisps[grid_coord->grid_index];
511 if (displacement_grid->disps != nullptr) {
512 const int grid_size = blender::bke::subdiv::grid_size_from_level(displacement_grid->level);
513 const int grid_x = lround(grid_coord->u * (grid_size - 1));
514 const int grid_y = lround(grid_coord->v * (grid_size - 1));
515 const int grid_element_index = grid_y * grid_size + grid_x;
516 copy_v3_v3(grid_element.displacement, displacement_grid->disps[grid_element_index]);
517 }
518 }
519
520 const GridPaintMask *grid_paint_masks = reshape_context->orig.grid_paint_masks;
521 if (grid_paint_masks != nullptr) {
522 const GridPaintMask *paint_mask_grid = &grid_paint_masks[grid_coord->grid_index];
523 if (paint_mask_grid->data != nullptr) {
524 const int grid_size = blender::bke::subdiv::grid_size_from_level(paint_mask_grid->level);
525 const int grid_x = lround(grid_coord->u * (grid_size - 1));
526 const int grid_y = lround(grid_coord->v * (grid_size - 1));
527 const int grid_element_index = grid_y * grid_size + grid_x;
528 grid_element.mask = paint_mask_grid->data[grid_element_index];
529 }
530 }
531
532 return grid_element;
533}
534
537/* -------------------------------------------------------------------- */
542 const GridCoord *grid_coord,
543 float r_P[3],
544 float r_tangent_matrix[3][3])
545{
546 float dPdu[3], dPdv[3];
547 const PTexCoord ptex_coord = multires_reshape_grid_coord_to_ptex(reshape_context, grid_coord);
548 blender::bke::subdiv::Subdiv *subdiv = reshape_context->subdiv;
550 subdiv, ptex_coord.ptex_face_index, ptex_coord.u, ptex_coord.v, r_P, dPdu, dPdv);
551
552 const int face_index = multires_reshape_grid_to_face_index(reshape_context,
553 grid_coord->grid_index);
554 const int corner = multires_reshape_grid_to_corner(reshape_context, grid_coord->grid_index);
556 reshape_context, face_index, corner, dPdu, dPdv, r_tangent_matrix);
557}
558
561/* -------------------------------------------------------------------- */
565static void allocate_displacement_grid(MDisps *displacement_grid, const int level)
566{
567 const int grid_size = blender::bke::subdiv::grid_size_from_level(level);
568 const int grid_area = grid_size * grid_size;
569 float(*disps)[3] = static_cast<float(*)[3]>(
570 MEM_calloc_arrayN(grid_area, sizeof(float[3]), "multires disps"));
571 if (displacement_grid->disps != nullptr) {
572 MEM_freeN(displacement_grid->disps);
573 }
574 /* TODO(sergey): Preserve data on the old level. */
575 displacement_grid->disps = disps;
576 displacement_grid->totdisp = grid_area;
577 displacement_grid->level = level;
578}
579
580static void ensure_displacement_grid(MDisps *displacement_grid, const int level)
581{
582 if (displacement_grid->disps != nullptr && displacement_grid->level >= level) {
583 return;
584 }
585 allocate_displacement_grid(displacement_grid, level);
586}
587
588static void ensure_displacement_grids(Mesh *mesh, const int grid_level)
589{
590 const int num_grids = mesh->corners_num;
591 MDisps *mdisps = static_cast<MDisps *>(
592 CustomData_get_layer_for_write(&mesh->corner_data, CD_MDISPS, mesh->corners_num));
593 for (int grid_index = 0; grid_index < num_grids; grid_index++) {
594 ensure_displacement_grid(&mdisps[grid_index], grid_level);
595 }
596}
597
598static void ensure_mask_grids(Mesh *mesh, const int level)
599{
600 GridPaintMask *grid_paint_masks = static_cast<GridPaintMask *>(
601 CustomData_get_layer_for_write(&mesh->corner_data, CD_GRID_PAINT_MASK, mesh->corners_num));
602 if (grid_paint_masks == nullptr) {
603 return;
604 }
605 const int num_grids = mesh->corners_num;
606 const int grid_size = blender::bke::subdiv::grid_size_from_level(level);
607 const int grid_area = grid_size * grid_size;
608 for (int grid_index = 0; grid_index < num_grids; grid_index++) {
609 GridPaintMask *grid_paint_mask = &grid_paint_masks[grid_index];
610 if (grid_paint_mask->level >= level) {
611 continue;
612 }
613 grid_paint_mask->level = level;
614 if (grid_paint_mask->data) {
615 MEM_freeN(grid_paint_mask->data);
616 }
617 /* TODO(sergey): Preserve data on the old level. */
618 grid_paint_mask->data = static_cast<float *>(
619 MEM_calloc_arrayN(grid_area, sizeof(float), "gpm.data"));
620 }
621}
622
623void multires_reshape_ensure_grids(Mesh *mesh, const int level)
624{
625 ensure_displacement_grids(mesh, level);
626 ensure_mask_grids(mesh, level);
627}
628
631/* -------------------------------------------------------------------- */
636{
637 const MDisps *mdisps = reshape_context->mdisps;
638 const GridPaintMask *grid_paint_masks = reshape_context->grid_paint_masks;
639
640 MDisps *orig_mdisps = static_cast<MDisps *>(MEM_dupallocN(mdisps));
641 GridPaintMask *orig_grid_paint_masks = nullptr;
642 if (grid_paint_masks != nullptr) {
643 orig_grid_paint_masks = static_cast<GridPaintMask *>(MEM_dupallocN(grid_paint_masks));
644 }
645
646 const int num_grids = reshape_context->num_grids;
647 for (int grid_index = 0; grid_index < num_grids; grid_index++) {
648 MDisps *orig_grid = &orig_mdisps[grid_index];
649 /* Ignore possibly invalid/non-allocated original grids. They will be replaced with 0 original
650 * data when accessed during reshape process.
651 * Reshape process will ensure all grids are on top level, but that happens on separate set of
652 * grids which eventually replaces original one. */
653 if (orig_grid->disps != nullptr) {
654 orig_grid->disps = static_cast<float(*)[3]>(MEM_dupallocN(orig_grid->disps));
655 }
656 if (orig_grid_paint_masks != nullptr) {
657 GridPaintMask *orig_paint_mask_grid = &orig_grid_paint_masks[grid_index];
658 if (orig_paint_mask_grid->data != nullptr) {
659 orig_paint_mask_grid->data = static_cast<float *>(
660 MEM_dupallocN(orig_paint_mask_grid->data));
661 }
662 }
663 }
664
665 reshape_context->orig.mdisps = orig_mdisps;
666 reshape_context->orig.grid_paint_masks = orig_grid_paint_masks;
667}
668
669using ForeachGridCoordinateCallback = void (*)(const MultiresReshapeContext *reshape_context,
670 const GridCoord *grid_coord,
671 void *userdata_v);
672
682
683static void foreach_grid_face_coordinate_task(void *__restrict userdata_v,
684 const int face_index,
685 const TaskParallelTLS *__restrict /*tls*/)
686{
687 ForeachGridCoordinateTaskData *data = static_cast<ForeachGridCoordinateTaskData *>(userdata_v);
688
689 const MultiresReshapeContext *reshape_context = data->reshape_context;
690
691 const blender::OffsetIndices faces = reshape_context->base_faces;
692 const int grid_size = data->grid_size;
693 const float grid_size_1_inv = 1.0f / (float(grid_size) - 1.0f);
694
695 const int num_corners = faces[face_index].size();
696 int grid_index = reshape_context->face_start_grid_index[face_index];
697 for (int corner = 0; corner < num_corners; ++corner, ++grid_index) {
698 for (int y = 0; y < grid_size; ++y) {
699 const float v = float(y) * grid_size_1_inv;
700 for (int x = 0; x < grid_size; ++x) {
701 const float u = float(x) * grid_size_1_inv;
702
703 GridCoord grid_coord;
704 grid_coord.grid_index = grid_index;
705 grid_coord.u = u;
706 grid_coord.v = v;
707
708 data->callback(data->reshape_context, &grid_coord, data->callback_userdata_v);
709 }
710 }
711 }
712}
713
714/* Run given callback for every grid coordinate at a given level. */
715static void foreach_grid_coordinate(const MultiresReshapeContext *reshape_context,
716 const int level,
718 void *userdata_v)
719{
721 data.reshape_context = reshape_context;
723 data.grid_size_1_inv = 1.0f / (float(data.grid_size) - 1.0f);
724 data.callback = callback;
725 data.callback_userdata_v = userdata_v;
726
727 TaskParallelSettings parallel_range_settings;
728 BLI_parallel_range_settings_defaults(&parallel_range_settings);
729 parallel_range_settings.min_iter_per_thread = 1;
730
731 const Mesh *base_mesh = reshape_context->base_mesh;
732 const int num_faces = base_mesh->faces_num;
734 0, num_faces, &data, foreach_grid_face_coordinate_task, &parallel_range_settings);
735}
736
738 const MultiresReshapeContext *reshape_context,
739 const GridCoord *grid_coord,
740 void * /*userdata_v*/)
741{
742 float P[3];
743 float tangent_matrix[3][3];
744 multires_reshape_evaluate_limit_at_grid(reshape_context, grid_coord, P, tangent_matrix);
745
746 float inv_tangent_matrix[3][3];
747 invert_m3_m3(inv_tangent_matrix, tangent_matrix);
748
750 grid_coord);
751
752 float D[3];
753 sub_v3_v3v3(D, grid_element.displacement, P);
754
755 float tangent_D[3];
756 mul_v3_m3v3(tangent_D, inv_tangent_matrix, D);
757
758 copy_v3_v3(grid_element.displacement, tangent_D);
759}
760
762 const MultiresReshapeContext *reshape_context)
763{
764 foreach_grid_coordinate(reshape_context,
765 reshape_context->top.level,
767 nullptr);
768}
769
772/* -------------------------------------------------------------------- */
776/* TODO(sergey): Make foreach_grid_coordinate more accessible and move this functionality to
777 * its own file. */
778
780 const GridCoord *grid_coord,
781 void * /*userdata_v*/)
782{
783 float P[3];
784 float tangent_matrix[3][3];
785 multires_reshape_evaluate_limit_at_grid(reshape_context, grid_coord, P, tangent_matrix);
786
788 grid_coord);
789 float D[3];
790 mul_v3_m3v3(D, tangent_matrix, grid_element.displacement);
791
792 add_v3_v3v3(grid_element.displacement, P, D);
793}
794
796 const MultiresReshapeContext *reshape_context)
797{
799 reshape_context, reshape_context->top.level, assign_final_coords_from_mdisps, nullptr);
800}
801
803 const GridCoord *grid_coord,
804 void * /*userdata_v*/)
805{
806 float P[3];
807 float tangent_matrix[3][3];
808 multires_reshape_evaluate_limit_at_grid(reshape_context, grid_coord, P, tangent_matrix);
809
810 const ReshapeConstGridElement orig_grid_element =
811 multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord);
812
813 float D[3];
814 mul_v3_m3v3(D, tangent_matrix, orig_grid_element.displacement);
815
817 grid_coord);
818 add_v3_v3v3(grid_element.displacement, P, D);
819
820 if (grid_element.mask != nullptr) {
821 *grid_element.mask = orig_grid_element.mask;
822 }
823}
824
826 const MultiresReshapeContext *reshape_context)
827{
828 foreach_grid_coordinate(reshape_context,
829 reshape_context->top.level,
831 nullptr);
832}
833
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:331
#define BLI_assert(a)
Definition BLI_assert.h:50
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:230
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ CD_GRID_PAINT_MASK
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
ATTR_WARN_UNUSED_RESULT const BMVert * v
AttributeSet attributes
const Depsgraph * depsgraph
DEGForeachIDComponentCallback callback
draw_view in_light_buf[] float
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:43
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
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)
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)
void(*)(const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord, void *userdata_v) ForeachGridCoordinateCallback
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:192
BLI_INLINE void rotate_grid_to_quad(int corner, float grid_u, float grid_v, float *r_quad_u, float *r_quad_v)
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:219
ForeachGridCoordinateCallback callback
const MultiresReshapeContext * reshape_context
float(* disps)[3]
int corners_num
CustomData corner_data
int faces_num
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
struct MultiresReshapeContext::@92 top
struct MultiresReshapeContext::@91 reshape
blender::Span< int > base_corner_verts
MultiresModifierData * mmd
struct MultiresReshapeContext::@93 orig
blender::bke::subdiv::Subdiv * subdiv