Blender V5.0
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_math_matrix.hh"
20#include "BLI_math_vector.h"
21#include "BLI_task.h"
22
23#include "BKE_attribute.hh"
24#include "BKE_customdata.hh"
25#include "BKE_mesh_runtime.hh"
26#include "BKE_multires.hh"
27#include "BKE_subdiv.hh"
28#include "BKE_subdiv_ccg.hh"
29#include "BKE_subdiv_eval.hh"
30
32
33/* -------------------------------------------------------------------- */
36
38 /*const*/ Object *object,
39 const MultiresModifierData *mmd)
40{
41 using namespace blender::bke;
42 Mesh *base_mesh;
43
44 if (depsgraph != nullptr) {
46 Object *object_eval = DEG_get_evaluated(depsgraph, object);
47 base_mesh = mesh_get_eval_deform(depsgraph, scene_eval, object_eval, &CD_MASK_BAREMESH);
48 }
49 else {
50 base_mesh = (Mesh *)object->data;
51 }
52
53 subdiv::Settings subdiv_settings;
54 BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
55 subdiv::Subdiv *subdiv = subdiv::new_from_mesh(&subdiv_settings, base_mesh);
56 if (!subdiv) {
57 return nullptr;
58 }
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.reinitialize(faces.size());
76 int num_grids = 0;
77 int num_ptex_faces = 0;
78 for (const int face_index : faces.index_range()) {
79 const int num_corners = faces[face_index].size();
80 reshape_context->face_start_grid_index[face_index] = num_grids;
81 num_grids += num_corners;
82 num_ptex_faces += (num_corners == 4) ? 1 : num_corners;
83 }
84
85 reshape_context->grid_to_face_index.reinitialize(num_grids);
86 reshape_context->ptex_start_grid_index.reinitialize(num_ptex_faces);
87 for (int face_index = 0, grid_index = 0, ptex_index = 0; face_index < faces.size(); ++face_index)
88 {
89 const int num_corners = faces[face_index].size();
90 const int num_face_ptex_faces = (num_corners == 4) ? 1 : num_corners;
91 for (int i = 0; i < num_face_ptex_faces; ++i) {
92 reshape_context->ptex_start_grid_index[ptex_index + i] = grid_index + i;
93 }
94 for (int corner = 0; corner < num_corners; ++corner, ++grid_index) {
95 reshape_context->grid_to_face_index[grid_index] = face_index;
96 }
97 ptex_index += num_face_ptex_faces;
98 }
99
100 /* Store number of grids, which will be used for sanity checks. */
101 reshape_context->num_grids = num_grids;
102}
103
105{
106 Mesh *base_mesh = reshape_context->base_mesh;
107 reshape_context->mdisps = static_cast<MDisps *>(
109 reshape_context->grid_paint_masks = static_cast<GridPaintMask *>(CustomData_get_layer_for_write(
110 &base_mesh->corner_data, CD_GRID_PAINT_MASK, base_mesh->corners_num));
111}
112
113static void context_init_common(MultiresReshapeContext *reshape_context)
114{
115 BLI_assert(reshape_context->subdiv != nullptr);
116 BLI_assert(reshape_context->base_mesh != nullptr);
117
119 reshape_context->subdiv);
120
121 context_init_lookup(reshape_context);
122 context_init_grid_pointers(reshape_context);
123}
124
125static bool context_is_valid(MultiresReshapeContext *reshape_context)
126{
127 if (reshape_context->mdisps == nullptr) {
128 /* Multi-resolution displacement has been removed before current changes were applies. */
129 return false;
130 }
131 return true;
132}
133
135{
136 const bool is_valid = context_is_valid(reshape_context);
137 if (!is_valid) {
138 multires_reshape_context_free(reshape_context);
139 }
140 return is_valid;
141}
142
144 Depsgraph *depsgraph,
145 Object *object,
147{
148 context_zero(reshape_context);
149
150 const bool use_render_params = false;
152 Mesh *base_mesh = (Mesh *)object->data;
153
154 reshape_context->depsgraph = depsgraph;
155 reshape_context->object = object;
156 reshape_context->mmd = mmd;
157
158 reshape_context->base_mesh = base_mesh;
159 reshape_context->base_positions = base_mesh->vert_positions();
160 reshape_context->base_edges = base_mesh->edges();
161 reshape_context->base_faces = base_mesh->faces();
162 reshape_context->base_corner_verts = base_mesh->corner_verts();
163 reshape_context->base_corner_edges = base_mesh->corner_edges();
164
165 reshape_context->subdiv = multires_reshape_create_subdiv(nullptr, object, mmd);
166 if (!reshape_context->subdiv) {
167 return false;
168 }
169 reshape_context->need_free_subdiv = true;
170
171 reshape_context->reshape.level = multires_get_level(
172 scene_eval, object, mmd, use_render_params, true);
174 reshape_context->reshape.level);
175
176 reshape_context->top.level = mmd->totlvl;
178 reshape_context->top.level);
179
180 context_init_common(reshape_context);
181
182 return context_verify_or_free(reshape_context);
183}
184
186 Depsgraph *depsgraph,
187 Object *object,
189{
190 using namespace blender;
191 using namespace blender::bke;
192 context_zero(reshape_context);
193
194 const bool use_render_params = false;
196 Mesh *base_mesh = (Mesh *)object->data;
197
198 reshape_context->depsgraph = depsgraph;
199 reshape_context->object = object;
200 reshape_context->mmd = mmd;
201
202 reshape_context->base_mesh = base_mesh;
203 reshape_context->base_positions = base_mesh->vert_positions();
204 reshape_context->base_edges = base_mesh->edges();
205 reshape_context->base_faces = base_mesh->faces();
206 reshape_context->base_corner_verts = base_mesh->corner_verts();
207 reshape_context->base_corner_edges = base_mesh->corner_edges();
208
209 reshape_context->subdiv = multires_reshape_create_subdiv(depsgraph, object, mmd);
210 if (!reshape_context->subdiv) {
211 return false;
212 }
213 reshape_context->need_free_subdiv = true;
214
215 reshape_context->reshape.level = multires_get_level(
216 scene_eval, object, mmd, use_render_params, true);
218 reshape_context->reshape.level);
219
220 reshape_context->top.level = mmd->totlvl;
221 reshape_context->top.grid_size = subdiv::grid_size_from_level(reshape_context->top.level);
222
223 const bke::AttributeAccessor attributes = base_mesh->attributes();
224 reshape_context->cd_vertex_crease = *attributes.lookup<float>("crease_vert", AttrDomain::Point);
225 reshape_context->cd_edge_crease = *attributes.lookup<float>("crease_edge", AttrDomain::Edge);
226
227 context_init_common(reshape_context);
228
229 return context_verify_or_free(reshape_context);
230}
231
233 SubdivCCG *subdiv_ccg,
234 Mesh *base_mesh,
235 int top_level)
236{
237 context_zero(reshape_context);
238
239 reshape_context->base_mesh = base_mesh;
240 reshape_context->base_positions = base_mesh->vert_positions();
241 reshape_context->base_edges = base_mesh->edges();
242 reshape_context->base_faces = base_mesh->faces();
243 reshape_context->base_corner_verts = base_mesh->corner_verts();
244 reshape_context->base_corner_edges = base_mesh->corner_edges();
245
246 reshape_context->subdiv = subdiv_ccg->subdiv;
247 reshape_context->need_free_subdiv = false;
248
249 reshape_context->reshape.level = subdiv_ccg->level;
251 reshape_context->reshape.level);
252
253 reshape_context->top.level = top_level;
255 reshape_context->top.level);
256
257 context_init_common(reshape_context);
258
259 return context_verify_or_free(reshape_context);
260}
261
263 Object *object,
265 int top_level)
266{
268
270 reshape_context, object, mmd, subdiv, top_level);
271
272 reshape_context->need_free_subdiv = true;
273
274 return result;
275}
276
278 Object *object,
281 int top_level)
282{
283 using namespace blender;
284 using namespace blender::bke;
285 context_zero(reshape_context);
286
287 Mesh *base_mesh = (Mesh *)object->data;
288
289 reshape_context->mmd = mmd;
290 reshape_context->base_mesh = base_mesh;
291 reshape_context->base_positions = base_mesh->vert_positions();
292 reshape_context->base_edges = base_mesh->edges();
293 reshape_context->base_faces = base_mesh->faces();
294 reshape_context->base_corner_verts = base_mesh->corner_verts();
295 reshape_context->base_corner_edges = base_mesh->corner_edges();
296
297 const bke::AttributeAccessor attributes = base_mesh->attributes();
298 reshape_context->cd_vertex_crease = *attributes.lookup<float>("crease_vert", AttrDomain::Point);
299
300 reshape_context->subdiv = subdiv;
301 reshape_context->need_free_subdiv = false;
302
303 reshape_context->reshape.level = mmd->totlvl;
305 reshape_context->reshape.level);
306
307 reshape_context->top.level = top_level;
308 reshape_context->top.grid_size = subdiv::grid_size_from_level(reshape_context->top.level);
309
310 context_init_common(reshape_context);
311
312 return context_verify_or_free(reshape_context);
313}
314
316{
317 MDisps *orig_mdisps = reshape_context->orig.mdisps;
318 GridPaintMask *orig_grid_paint_masks = reshape_context->orig.grid_paint_masks;
319
320 if (orig_mdisps == nullptr && orig_grid_paint_masks == nullptr) {
321 return;
322 }
323
324 const int num_grids = reshape_context->num_grids;
325 for (int grid_index = 0; grid_index < num_grids; grid_index++) {
326 if (orig_mdisps != nullptr) {
327 MDisps *orig_grid = &orig_mdisps[grid_index];
328 MEM_SAFE_FREE(orig_grid->disps);
329 }
330 if (orig_grid_paint_masks != nullptr) {
331 GridPaintMask *orig_paint_mask_grid = &orig_grid_paint_masks[grid_index];
332 MEM_SAFE_FREE(orig_paint_mask_grid->data);
333 }
334 }
335
336 MEM_SAFE_FREE(orig_mdisps);
337 MEM_SAFE_FREE(orig_grid_paint_masks);
338
339 reshape_context->orig.mdisps = nullptr;
340 reshape_context->orig.grid_paint_masks = nullptr;
341}
342
344{
345 if (reshape_context->need_free_subdiv) {
346 blender::bke::subdiv::free(reshape_context->subdiv);
347 }
348
350}
351
353
354/* -------------------------------------------------------------------- */
357
359 int grid_index)
360{
361 BLI_assert(grid_index >= 0);
362 BLI_assert(grid_index < reshape_context->num_grids);
363
364 /* TODO(sergey): Optimization: when SubdivCCG is known we can calculate face index using
365 * SubdivCCG::grid_faces and SubdivCCG::faces, saving memory used by grid_to_face_index. */
366
367 return reshape_context->grid_to_face_index[grid_index];
368}
369
370int multires_reshape_grid_to_corner(const MultiresReshapeContext *reshape_context, int grid_index)
371{
372 BLI_assert(grid_index >= 0);
373 BLI_assert(grid_index < reshape_context->num_grids);
374
375 /* TODO(sergey): Optimization: when SubdivCCG is known we can calculate face index using
376 * SubdivCCG::grid_faces and SubdivCCG::faces, saving memory used by grid_to_face_index. */
377
378 const int face_index = multires_reshape_grid_to_face_index(reshape_context, grid_index);
379 return grid_index - reshape_context->face_start_grid_index[face_index];
380}
381
382bool multires_reshape_is_quad_face(const MultiresReshapeContext *reshape_context, int face_index)
383{
384 return reshape_context->base_faces[face_index].size() == 4;
385}
386
388 int grid_index)
389{
390 const int face_index = multires_reshape_grid_to_face_index(reshape_context, grid_index);
391 const int corner = multires_reshape_grid_to_corner(reshape_context, grid_index);
392 const bool is_quad = multires_reshape_is_quad_face(reshape_context, face_index);
393 return reshape_context->face_ptex_offset[face_index] + (is_quad ? 0 : corner);
394}
395
397 const GridCoord *grid_coord)
398{
399 PTexCoord ptex_coord;
400
401 ptex_coord.ptex_face_index = multires_reshape_grid_to_ptex_index(reshape_context,
402 grid_coord->grid_index);
403
404 float corner_u, corner_v;
406 grid_coord->u, grid_coord->v, &corner_u, &corner_v);
407
408 const int face_index = multires_reshape_grid_to_face_index(reshape_context,
409 grid_coord->grid_index);
410 const int corner = multires_reshape_grid_to_corner(reshape_context, grid_coord->grid_index);
411 if (multires_reshape_is_quad_face(reshape_context, face_index)) {
412 float grid_u, grid_v;
413 blender::bke::subdiv::ptex_face_uv_to_grid_uv(corner_u, corner_v, &grid_u, &grid_v);
415 corner, grid_u, grid_v, &ptex_coord.u, &ptex_coord.v);
416 }
417 else {
418 ptex_coord.u = corner_u;
419 ptex_coord.v = corner_v;
420 }
421
422 return ptex_coord;
423}
424
426 const PTexCoord *ptex_coord)
427{
428 GridCoord grid_coord;
429
430 const int start_grid_index = reshape_context->ptex_start_grid_index[ptex_coord->ptex_face_index];
431 const int face_index = reshape_context->grid_to_face_index[start_grid_index];
432
433 int corner_delta;
434 if (multires_reshape_is_quad_face(reshape_context, face_index)) {
436 ptex_coord->u, ptex_coord->v, &grid_coord.u, &grid_coord.v);
437 }
438 else {
439 corner_delta = 0;
440 grid_coord.u = ptex_coord->u;
441 grid_coord.v = ptex_coord->v;
442 }
443 grid_coord.grid_index = start_grid_index + corner_delta;
444
446 grid_coord.u, grid_coord.v, &grid_coord.u, &grid_coord.v);
447
448 return grid_coord;
449}
450
452 const int face_index,
453 const int corner,
454 const blender::float3 &dPdu,
455 const blender::float3 &dPdv,
456 blender::float3x3 &r_tangent_matrix)
457{
458 /* For a quad faces we would need to flip the tangent, since they will use
459 * use different coordinates within displacement grid compared to the ptex face. */
460 const bool is_quad = multires_reshape_is_quad_face(reshape_context, face_index);
461 const int tangent_corner = is_quad ? corner : 0;
462 BKE_multires_construct_tangent_matrix(r_tangent_matrix, dPdu, dPdv, tangent_corner);
463}
464
466 const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord)
467{
468 ReshapeGridElement grid_element = {nullptr, nullptr};
469
470 const int grid_size = reshape_context->top.grid_size;
471 const int grid_x = lround(grid_coord->u * (grid_size - 1));
472 const int grid_y = lround(grid_coord->v * (grid_size - 1));
473 const int grid_element_index = grid_y * grid_size + grid_x;
474
475 if (reshape_context->mdisps != nullptr) {
476 MDisps *displacement_grid = &reshape_context->mdisps[grid_coord->grid_index];
477 grid_element.displacement = reinterpret_cast<blender::float3 *>(
478 displacement_grid->disps[grid_element_index]);
479 }
480
481 if (reshape_context->grid_paint_masks != nullptr) {
482 GridPaintMask *grid_paint_mask = &reshape_context->grid_paint_masks[grid_coord->grid_index];
483 grid_element.mask = &grid_paint_mask->data[grid_element_index];
484 }
485
486 return grid_element;
487}
488
490 const MultiresReshapeContext *reshape_context, const PTexCoord *ptex_coord)
491{
492 GridCoord grid_coord = multires_reshape_ptex_coord_to_grid(reshape_context, ptex_coord);
493 return multires_reshape_grid_element_for_grid_coord(reshape_context, &grid_coord);
494}
495
497 const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord)
498{
499 ReshapeConstGridElement grid_element = {{0.0f, 0.0f, 0.0f}, 0.0f};
500
501 const MDisps *mdisps = reshape_context->orig.mdisps;
502 if (mdisps != nullptr) {
503 const MDisps *displacement_grid = &mdisps[grid_coord->grid_index];
504 if (displacement_grid->disps != nullptr) {
505 const int grid_size = blender::bke::subdiv::grid_size_from_level(displacement_grid->level);
506 const int grid_x = lround(grid_coord->u * (grid_size - 1));
507 const int grid_y = lround(grid_coord->v * (grid_size - 1));
508 const int grid_element_index = grid_y * grid_size + grid_x;
509 grid_element.displacement = displacement_grid->disps[grid_element_index];
510 }
511 }
512
513 const GridPaintMask *grid_paint_masks = reshape_context->orig.grid_paint_masks;
514 if (grid_paint_masks != nullptr) {
515 const GridPaintMask *paint_mask_grid = &grid_paint_masks[grid_coord->grid_index];
516 if (paint_mask_grid->data != nullptr) {
517 const int grid_size = blender::bke::subdiv::grid_size_from_level(paint_mask_grid->level);
518 const int grid_x = lround(grid_coord->u * (grid_size - 1));
519 const int grid_y = lround(grid_coord->v * (grid_size - 1));
520 const int grid_element_index = grid_y * grid_size + grid_x;
521 grid_element.mask = paint_mask_grid->data[grid_element_index];
522 }
523 }
524
525 return grid_element;
526}
527
529
530/* -------------------------------------------------------------------- */
533
535 const MultiresReshapeContext *reshape_context,
536 const GridCoord *grid_coord,
537 blender::float3 &r_P,
538 blender::float3x3 &r_tangent_matrix)
539{
540 blender::float3 dPdu;
541 blender::float3 dPdv;
542 const PTexCoord ptex_coord = multires_reshape_grid_coord_to_ptex(reshape_context, grid_coord);
543 blender::bke::subdiv::Subdiv *subdiv = reshape_context->subdiv;
545 subdiv, ptex_coord.ptex_face_index, ptex_coord.u, ptex_coord.v, r_P, dPdu, dPdv);
546
547 const int face_index = multires_reshape_grid_to_face_index(reshape_context,
548 grid_coord->grid_index);
549 const int corner = multires_reshape_grid_to_corner(reshape_context, grid_coord->grid_index);
551 reshape_context, face_index, corner, dPdu, dPdv, r_tangent_matrix);
552}
553
555
556/* -------------------------------------------------------------------- */
559
560static void allocate_displacement_grid(MDisps *displacement_grid, const int level)
561{
562 const int grid_size = blender::bke::subdiv::grid_size_from_level(level);
563 const int grid_area = grid_size * grid_size;
564 float (*disps)[3] = MEM_calloc_arrayN<float[3]>(grid_area, "multires disps");
565 if (displacement_grid->disps != nullptr) {
566 MEM_freeN(displacement_grid->disps);
567 }
568 /* TODO(sergey): Preserve data on the old level. */
569 displacement_grid->disps = disps;
570 displacement_grid->totdisp = grid_area;
571 displacement_grid->level = level;
572}
573
574static void ensure_displacement_grid(MDisps *displacement_grid, const int level)
575{
576 if (displacement_grid->disps != nullptr && displacement_grid->level >= level) {
577 return;
578 }
579 allocate_displacement_grid(displacement_grid, level);
580}
581
582static void ensure_displacement_grids(Mesh *mesh, const int grid_level)
583{
584 const int num_grids = mesh->corners_num;
585 MDisps *mdisps = static_cast<MDisps *>(
586 CustomData_get_layer_for_write(&mesh->corner_data, CD_MDISPS, mesh->corners_num));
587 for (int grid_index = 0; grid_index < num_grids; grid_index++) {
588 ensure_displacement_grid(&mdisps[grid_index], grid_level);
589 }
590}
591
592static void ensure_mask_grids(Mesh *mesh, const int level)
593{
594 GridPaintMask *grid_paint_masks = static_cast<GridPaintMask *>(
595 CustomData_get_layer_for_write(&mesh->corner_data, CD_GRID_PAINT_MASK, mesh->corners_num));
596 if (grid_paint_masks == nullptr) {
597 return;
598 }
599 const int num_grids = mesh->corners_num;
600 const int grid_size = blender::bke::subdiv::grid_size_from_level(level);
601 const int grid_area = grid_size * grid_size;
602 for (int grid_index = 0; grid_index < num_grids; grid_index++) {
603 GridPaintMask *grid_paint_mask = &grid_paint_masks[grid_index];
604 if (grid_paint_mask->level >= level) {
605 continue;
606 }
607 grid_paint_mask->level = level;
608 if (grid_paint_mask->data) {
609 MEM_freeN(grid_paint_mask->data);
610 }
611 /* TODO(sergey): Preserve data on the old level. */
612 grid_paint_mask->data = MEM_calloc_arrayN<float>(grid_area, "gpm.data");
613 }
614}
615
617{
619 ensure_mask_grids(mesh, level);
620}
621
623
624/* -------------------------------------------------------------------- */
627
629{
630 const MDisps *mdisps = reshape_context->mdisps;
631 const GridPaintMask *grid_paint_masks = reshape_context->grid_paint_masks;
632
633 MDisps *orig_mdisps = static_cast<MDisps *>(MEM_dupallocN(mdisps));
634 GridPaintMask *orig_grid_paint_masks = nullptr;
635 if (grid_paint_masks != nullptr) {
636 orig_grid_paint_masks = static_cast<GridPaintMask *>(MEM_dupallocN(grid_paint_masks));
637 }
638
639 const int num_grids = reshape_context->num_grids;
640 for (int grid_index = 0; grid_index < num_grids; grid_index++) {
641 MDisps *orig_grid = &orig_mdisps[grid_index];
642 /* Ignore possibly invalid/non-allocated original grids. They will be replaced with 0 original
643 * data when accessed during reshape process.
644 * Reshape process will ensure all grids are on top level, but that happens on separate set of
645 * grids which eventually replaces original one. */
646 if (orig_grid->disps != nullptr) {
647 orig_grid->disps = static_cast<float (*)[3]>(MEM_dupallocN(orig_grid->disps));
648 }
649 if (orig_grid_paint_masks != nullptr) {
650 GridPaintMask *orig_paint_mask_grid = &orig_grid_paint_masks[grid_index];
651 if (orig_paint_mask_grid->data != nullptr) {
652 orig_paint_mask_grid->data = static_cast<float *>(
653 MEM_dupallocN(orig_paint_mask_grid->data));
654 }
655 }
656 }
657
658 reshape_context->orig.mdisps = orig_mdisps;
659 reshape_context->orig.grid_paint_masks = orig_grid_paint_masks;
660}
661
662using ForeachGridCoordinateCallback = void (*)(const MultiresReshapeContext *reshape_context,
663 const GridCoord *grid_coord,
664 void *userdata_v);
665
675
676static void foreach_grid_face_coordinate_task(void *__restrict userdata_v,
677 const int face_index,
678 const TaskParallelTLS *__restrict /*tls*/)
679{
681
682 const MultiresReshapeContext *reshape_context = data->reshape_context;
683
684 const blender::OffsetIndices faces = reshape_context->base_faces;
685 const int grid_size = data->grid_size;
686 const float grid_size_1_inv = 1.0f / (float(grid_size) - 1.0f);
687
688 const int num_corners = faces[face_index].size();
689 int grid_index = reshape_context->face_start_grid_index[face_index];
690 for (int corner = 0; corner < num_corners; ++corner, ++grid_index) {
691 for (int y = 0; y < grid_size; ++y) {
692 const float v = float(y) * grid_size_1_inv;
693 for (int x = 0; x < grid_size; ++x) {
694 const float u = float(x) * grid_size_1_inv;
695
696 GridCoord grid_coord;
697 grid_coord.grid_index = grid_index;
698 grid_coord.u = u;
699 grid_coord.v = v;
700
701 data->callback(data->reshape_context, &grid_coord, data->callback_userdata_v);
702 }
703 }
704 }
705}
706
707/* Run given callback for every grid coordinate at a given level. */
708static void foreach_grid_coordinate(const MultiresReshapeContext *reshape_context,
709 const int level,
711 void *userdata_v)
712{
714 data.reshape_context = reshape_context;
716 data.grid_size_1_inv = 1.0f / (float(data.grid_size) - 1.0f);
717 data.callback = callback;
718 data.callback_userdata_v = userdata_v;
719
720 TaskParallelSettings parallel_range_settings;
721 BLI_parallel_range_settings_defaults(&parallel_range_settings);
722 parallel_range_settings.min_iter_per_thread = 1;
723
724 const Mesh *base_mesh = reshape_context->base_mesh;
725 const int num_faces = base_mesh->faces_num;
727 0, num_faces, &data, foreach_grid_face_coordinate_task, &parallel_range_settings);
728}
729
731 const MultiresReshapeContext *reshape_context,
732 const GridCoord *grid_coord,
733 void * /*userdata_v*/)
734{
736 blender::float3x3 tangent_matrix;
738 reshape_context, grid_coord, P, tangent_matrix);
739
740 const blender::float3x3 inv_tangent_matrix = blender::math::invert(tangent_matrix);
741
743 grid_coord);
744
745 blender::float3 D = *grid_element.displacement - P;
746
747 blender::float3 tangent_D = blender::math::transform_direction(inv_tangent_matrix, D);
748
749 *grid_element.displacement = tangent_D;
750}
751
753 const MultiresReshapeContext *reshape_context)
754{
755 foreach_grid_coordinate(reshape_context,
756 reshape_context->top.level,
758 nullptr);
759}
760
762
763/* -------------------------------------------------------------------- */
766
767/* TODO(sergey): Make foreach_grid_coordinate more accessible and move this functionality to
768 * its own file. */
769
771 const GridCoord *grid_coord,
772 void * /*userdata_v*/)
773{
775 blender::float3x3 tangent_matrix;
777 reshape_context, grid_coord, P, tangent_matrix);
778
780 grid_coord);
782 *grid_element.displacement);
783
784 *grid_element.displacement = P + D;
785}
786
788 const MultiresReshapeContext *reshape_context)
789{
791 reshape_context, reshape_context->top.level, assign_final_coords_from_mdisps, nullptr);
792}
793
795 const GridCoord *grid_coord,
796 void * /*userdata_v*/)
797{
799 blender::float3x3 tangent_matrix;
801 reshape_context, grid_coord, P, tangent_matrix);
802
803 const ReshapeConstGridElement orig_grid_element =
804 multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord);
805
807 orig_grid_element.displacement);
808
810 grid_coord);
811 *grid_element.displacement = P + D;
812
813 if (grid_element.mask != nullptr) {
814 *grid_element.mask = orig_grid_element.mask;
815 }
816}
817
819 const MultiresReshapeContext *reshape_context)
820{
821 foreach_grid_coordinate(reshape_context,
822 reshape_context->top.level,
824 nullptr);
825}
826
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(blender::float3x3 &tangent_matrix, const blender::float3 &dPdu, const blender::float3 &dPdv, int corner)
int multires_get_level(const Scene *scene, const Object *ob, const MultiresModifierData *mmd, bool render, bool ignore_simplify)
Definition multires.cc:205
#define D
#define BLI_assert(a)
Definition BLI_assert.h:46
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.
#define MEM_SAFE_FREE(v)
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v
BPy_StructRNA * depsgraph
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:419
AttributeSet attributes
GAttributeReader lookup(const StringRef attribute_id) const
nullptr float
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
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)
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_tangent_matrix_for_corner(const MultiresReshapeContext *reshape_context, const int face_index, const int corner, const blender::float3 &dPdu, const blender::float3 &dPdv, blender::float3x3 &r_tangent_matrix)
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)
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)
static void ensure_mask_grids(Mesh *mesh, const int level)
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
bool eval_begin_from_mesh(Subdiv *subdiv, const Mesh *mesh, eSubdivEvaluatorType evaluator_type, Span< float3 > coarse_vert_positions={}, OpenSubdiv_EvaluatorCache *evaluator_cache=nullptr)
BLI_INLINE void rotate_grid_to_quad(int corner, float grid_u, float grid_v, float *r_quad_u, float *r_quad_v)
Subdiv * new_from_mesh(const Settings *settings, const Mesh *mesh)
Definition subdiv.cc:131
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)
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)
Span< int > face_ptex_offset_get(Subdiv *subdiv)
Definition subdiv.cc:214
Mesh * mesh_get_eval_deform(Depsgraph *depsgraph, const Scene *scene, Object *ob, const CustomData_MeshMasks *dataMask)
CartesianBasis invert(const CartesianBasis &basis)
VecBase< T, 3 > transform_direction(const MatBase< T, 3, 3 > &mat, const VecBase< T, 3 > &direction)
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
ForeachGridCoordinateCallback callback
const MultiresReshapeContext * reshape_context
float(* disps)[3]
int corners_num
CustomData corner_data
int faces_num
struct MultiresReshapeContext::@114377305000353127144042327223234020156043120202 reshape
blender::bke::subdiv::Subdiv * subdiv
blender::Span< int > face_ptex_offset
struct MultiresReshapeContext::@204160262355230072153262361266331214205042063262 top
blender::VArraySpan< float > cd_vertex_crease
blender::Array< int > ptex_start_grid_index
blender::Span< int > base_corner_edges
GridPaintMask * grid_paint_masks
blender::VArraySpan< float > cd_edge_crease
struct MultiresReshapeContext::@224024350043126210016356042105244264040105373265 orig
blender::OffsetIndices< int > base_faces
blender::Span< blender::int2 > base_edges
blender::Array< int > face_start_grid_index
blender::Span< blender::float3 > base_positions
blender::Span< int > base_corner_verts
blender::Array< int > grid_to_face_index
MultiresModifierData * mmd
blender::float3 * displacement
blender::bke::subdiv::Subdiv * subdiv
i
Definition text_draw.cc:230