Blender V4.5
MOD_normal_edit.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstring>
10
11#include "MEM_guardedalloc.h"
12
13#include "BLI_utildefines.h"
14
15#include "BLI_bitmap.h"
16#include "BLI_math_matrix.h"
17#include "BLI_math_vector.h"
18#include "BLI_math_vector.hh"
19
20#include "BLT_translation.hh"
21
22#include "DNA_defaults.h"
23#include "DNA_mesh_types.h"
24#include "DNA_object_types.h"
25#include "DNA_screen_types.h"
26
27#include "BKE_attribute.hh"
28#include "BKE_deform.hh"
29#include "BKE_lib_id.hh"
30#include "BKE_lib_query.hh"
31#include "BKE_mesh.hh"
32
33#include "UI_interface.hh"
34#include "UI_resources.hh"
35
36#include "RNA_access.hh"
37#include "RNA_prototypes.hh"
38
39#include "MOD_ui_common.hh"
40#include "MOD_util.hh"
41
43 Object *ob,
44 Object *ob_center,
45 const float offset[3],
46 const int verts_num,
47 float (*r_cos)[3],
48 blender::float3 *r_size)
49{
50 using namespace blender;
51 float min_co[3], max_co[3];
52 float diff[3];
53 bool do_diff = false;
54
55 INIT_MINMAX(min_co, max_co);
56
57 const Span<float3> positions = mesh->vert_positions();
58 for (int i = 0; i < mesh->verts_num; i++) {
59 copy_v3_v3(r_cos[i], positions[i]);
60 if (r_size != nullptr && ob_center == nullptr) {
61 minmax_v3v3_v3(min_co, max_co, r_cos[i]);
62 }
63 }
64
65 /* Get size (i.e. deformation of the spheroid generating normals),
66 * either from target object, or geometry. */
67 if (r_size != nullptr) {
68 if (ob_center != nullptr) {
69 /* Using 'scale' as 'size' here. The input object is typically an empty
70 * who's scale is used to define an ellipsoid instead of a simple sphere. */
71
72 /* Not we are not interested in signs here - they are even troublesome actually,
73 * due to security clamping! */
74 *r_size = blender::math::abs(blender::float3(ob_center->scale));
75 }
76 else {
77 /* Set size. */
78 sub_v3_v3v3(*r_size, max_co, min_co);
79 }
80
81 /* Error checks - we do not want one or more of our sizes to be null! */
82 if (is_zero_v3(*r_size)) {
83 *r_size = float3(1.0f);
84 }
85 else {
86 CLAMP_MIN((*r_size)[0], FLT_EPSILON);
87 CLAMP_MIN((*r_size)[1], FLT_EPSILON);
88 CLAMP_MIN((*r_size)[2], FLT_EPSILON);
89 }
90 }
91
92 if (ob_center != nullptr) {
93 float inv_obmat[4][4];
94
95 /* Translate our coordinates so that center of ob_center is at (0, 0, 0). */
96 /* Get ob_center (world) coordinates in ob local coordinates.
97 * No need to take into account ob_center's space here, see #44027. */
98 invert_m4_m4(inv_obmat, ob->object_to_world().ptr());
99 mul_v3_m4v3(diff, inv_obmat, ob_center->object_to_world().location());
101
102 do_diff = true;
103 }
104 else if (offset != nullptr && !is_zero_v3(offset)) {
105 negate_v3_v3(diff, offset);
106
107 do_diff = true;
108 }
109 /* Else, no need to change coordinates! */
110
111 if (do_diff) {
112 int i = verts_num;
113 while (i--) {
114 add_v3_v3(r_cos[i], diff);
115 }
116 }
117}
118
119/* Note this modifies nos_new in-place. */
120static void mix_normals(const float mix_factor,
121 const MDeformVert *dvert,
122 const int defgrp_index,
123 const bool use_invert_vgroup,
124 const float mix_limit,
125 const short mix_mode,
126 const int verts_num,
127 const blender::Span<int> corner_verts,
128 blender::float3 *nos_old,
129 blender::float3 *nos_new)
130{
131 /* Mix with org normals... */
132 float *facs = nullptr, *wfac;
133 blender::float3 *no_new, *no_old;
134 int i;
135
136 if (dvert) {
137 facs = MEM_malloc_arrayN<float>(size_t(corner_verts.size()), __func__);
139 defgrp_index,
140 verts_num,
141 corner_verts.data(),
142 corner_verts.size(),
143 use_invert_vgroup,
144 facs);
145 }
146
147 for (i = corner_verts.size(), no_new = nos_new, no_old = nos_old, wfac = facs; i--;
148 no_new++, no_old++, wfac++)
149 {
150 const float fac = facs ? *wfac * mix_factor : mix_factor;
151
152 switch (mix_mode) {
154 add_v3_v3(*no_new, *no_old);
155 normalize_v3(*no_new);
156 break;
158 sub_v3_v3(*no_new, *no_old);
159 normalize_v3(*no_new);
160 break;
162 mul_v3_v3(*no_new, *no_old);
163 normalize_v3(*no_new);
164 break;
166 break;
167 }
168
170 *no_new,
171 *no_old,
172 *no_new,
173 (mix_limit < float(M_PI)) ? min_ff(fac, mix_limit / angle_v3v3(*no_new, *no_old)) : fac);
174 }
175
176 MEM_SAFE_FREE(facs);
177}
178
179/* Check face normals and new loop normals are compatible, otherwise flip faces
180 * (and invert matching face normals). */
181static void faces_check_flip(Mesh &mesh,
183 const blender::Span<blender::float3> face_normals)
184{
185 using namespace blender;
186 const OffsetIndices faces = mesh.faces();
187 IndexMaskMemory memory;
188 const IndexMask faces_to_flip = IndexMask::from_predicate(
189 faces.index_range(), GrainSize(1024), memory, [&](const int i) {
190 const blender::IndexRange face = faces[i];
191 float norsum[3] = {0.0f};
192
193 for (const int64_t j : face) {
194 add_v3_v3(norsum, nos[j]);
195 }
196 if (!normalize_v3(norsum)) {
197 return false;
198 }
199
200 /* If average of new loop normals is opposed to face normal, flip face. */
201 if (dot_v3v3(face_normals[i], norsum) < 0.0f) {
202 nos.slice(faces[i].drop_front(1)).reverse();
203 return true;
204 }
205 return false;
206 });
207
208 bke::mesh_flip_faces(mesh, faces_to_flip);
209}
210
212 const ModifierEvalContext * /*ctx*/,
213 Object *ob,
214 Mesh *mesh,
217 const short mix_mode,
218 const float mix_factor,
219 const float mix_limit,
220 const MDeformVert *dvert,
221 const int defgrp_index,
222 const bool use_invert_vgroup,
223 blender::Span<blender::float3> vert_positions,
224 blender::MutableSpan<bool> sharp_edges,
225 blender::MutableSpan<int> corner_verts,
226 blender::MutableSpan<int> corner_edges,
228{
229 using namespace blender;
230 Object *ob_target = enmd->target;
231
232 const bool do_facenors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0;
233
234 float(*cos)[3] = MEM_malloc_arrayN<float[3]>(size_t(vert_positions.size()), __func__);
235 blender::Array<blender::float3> nos(corner_verts.size());
236 float3 size;
237
238 BLI_bitmap *done_verts = BLI_BITMAP_NEW(size_t(vert_positions.size()), __func__);
239
240 generate_vert_coordinates(mesh, ob, ob_target, enmd->offset, vert_positions.size(), cos, &size);
241
273 {
274 const float a = size[0], b = size[1], c = size[2];
275 const float m2 = (b * b) / (a * a);
276 const float n2 = (c * c) / (a * a);
277
278 /* We reuse cos to now store the ellipsoid-normal of the verts! */
279 for (const int64_t i : corner_verts.index_range()) {
280 const int vidx = corner_verts[i];
281 float *co = cos[vidx];
282
283 if (!BLI_BITMAP_TEST(done_verts, vidx)) {
284 const float x2 = co[0] * co[0];
285 const float y2 = co[1] * co[1];
286 const float z2 = co[2] * co[2];
287 const float a2 = x2 + (y2 / m2) + (z2 / n2);
288 const float b2 = (m2 * x2) + y2 + (m2 * z2 / n2);
289 const float c2 = (n2 * x2) + (n2 * y2 / m2) + z2;
290
291 co[0] /= a2;
292 co[1] /= b2;
293 co[2] /= c2;
294 normalize_v3(co);
295
296 BLI_BITMAP_ENABLE(done_verts, vidx);
297 }
298 nos[i] = co;
299 }
300 }
301
302 if (!corner_normals.is_empty()) {
303 mix_normals(mix_factor,
304 dvert,
305 defgrp_index,
306 use_invert_vgroup,
307 mix_limit,
308 mix_mode,
309 vert_positions.size(),
310 corner_verts,
311 corner_normals.data(),
312 nos.data());
313 }
314
315 if (do_facenors_fix) {
316 faces_check_flip(*mesh, nos, mesh->face_normals_true());
317 }
318 const bke::AttributeAccessor attributes = mesh->attributes();
319 const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
321 faces,
322 corner_verts,
323 corner_edges,
324 mesh->vert_to_face_map(),
325 mesh->vert_normals_true(),
326 mesh->face_normals_true(),
327 sharp_faces,
328 sharp_edges,
329 nos,
330 clnors);
331
332 MEM_freeN(cos);
333 MEM_freeN(done_verts);
334}
335
337 const ModifierEvalContext * /*ctx*/,
338 Object *ob,
339 Mesh *mesh,
342 const short mix_mode,
343 const float mix_factor,
344 const float mix_limit,
345 const MDeformVert *dvert,
346 const int defgrp_index,
347 const bool use_invert_vgroup,
348 const blender::Span<blender::float3> positions,
349 blender::MutableSpan<bool> sharp_edges,
350 blender::MutableSpan<int> corner_verts,
351 blender::MutableSpan<int> corner_edges,
353{
354 using namespace blender;
355 Object *ob_target = enmd->target;
356
357 const bool do_facenors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0;
358 const bool use_parallel_normals = (enmd->flag & MOD_NORMALEDIT_USE_DIRECTION_PARALLEL) != 0;
359
360 blender::Array<blender::float3> nos(corner_verts.size());
361
362 float target_co[3];
363 int i;
364
365 /* Get target's center coordinates in ob local coordinates. */
366 float mat[4][4];
367
368 invert_m4_m4(mat, ob->object_to_world().ptr());
369 mul_m4_m4m4(mat, mat, ob_target->object_to_world().ptr());
370 copy_v3_v3(target_co, mat[3]);
371
372 if (use_parallel_normals) {
373 float no[3];
374
375 sub_v3_v3v3(no, target_co, enmd->offset);
376 normalize_v3(no);
377
378 for (i = corner_verts.size(); i--;) {
379 copy_v3_v3(nos[i], no);
380 }
381 }
382 else {
383 float(*cos)[3] = MEM_malloc_arrayN<float[3]>(size_t(positions.size()), __func__);
384 generate_vert_coordinates(mesh, ob, ob_target, nullptr, positions.size(), cos, nullptr);
385
386 BLI_bitmap *done_verts = BLI_BITMAP_NEW(size_t(positions.size()), __func__);
387
388 /* We reuse cos to now store the 'to target' normal of the verts! */
389 for (const int64_t i : corner_verts.index_range()) {
390 const int vidx = corner_verts[i];
391 float *co = cos[vidx];
392
393 if (!BLI_BITMAP_TEST(done_verts, vidx)) {
394 sub_v3_v3v3(co, target_co, co);
395 normalize_v3(co);
396
397 BLI_BITMAP_ENABLE(done_verts, vidx);
398 }
399 nos[i] = co;
400 }
401
402 MEM_freeN(done_verts);
403 MEM_freeN(cos);
404 }
405
406 if (!corner_normals.is_empty()) {
407 mix_normals(mix_factor,
408 dvert,
409 defgrp_index,
410 use_invert_vgroup,
411 mix_limit,
412 mix_mode,
413 positions.size(),
414 corner_verts,
415 corner_normals.data(),
416 nos.data());
417 }
418
419 if (do_facenors_fix) {
420 faces_check_flip(*mesh, nos, mesh->face_normals_true());
421 }
422 const bke::AttributeAccessor attributes = mesh->attributes();
423 const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
425 faces,
426 corner_verts,
427 corner_edges,
428 mesh->vert_to_face_map(),
429 mesh->vert_normals_true(),
430 mesh->face_normals_true(),
431 sharp_faces,
432 sharp_edges,
433 nos,
434 clnors);
435}
436
438{
439 if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
440 return true;
441 }
442 if ((enmd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) && enmd->target) {
443 return true;
444 }
445 return false;
446}
447
449{
450 if (is_valid_target(enmd)) {
451 return true;
452 }
453 BKE_modifier_set_error(ob, (ModifierData *)enmd, "Invalid target settings");
454 return false;
455}
456
458 const ModifierEvalContext *ctx,
459 Object *ob,
460 Mesh *mesh)
461{
462 using namespace blender;
463 const bool use_invert_vgroup = ((enmd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0);
464 const bool use_current_clnors = !((enmd->mix_mode == MOD_NORMALEDIT_MIX_COPY) &&
465 (enmd->mix_factor == 1.0f) && (enmd->defgrp_name[0] == '\0') &&
466 (enmd->mix_limit == float(M_PI)));
467
468 /* Do not run that modifier at all if auto-smooth is disabled! */
469 if (!is_valid_target_with_error(ctx->object, enmd) || mesh->corners_num == 0) {
470 return mesh;
471 }
472
473 Mesh *result;
474 if (mesh->edges().data() == ((Mesh *)ob->data)->edges().data()) {
475 /* We need to duplicate data here, otherwise setting custom normals
476 * (which may also affect sharp edges) could
477 * modify original mesh, see #43671. */
478 result = (Mesh *)BKE_id_copy_ex(nullptr, &mesh->id, nullptr, LIB_ID_COPY_LOCALIZE);
479 }
480 else {
481 result = mesh;
482 }
483
484 const blender::Span<blender::float3> positions = result->vert_positions();
485 const OffsetIndices faces = result->faces();
486 blender::MutableSpan<int> corner_verts = result->corner_verts_for_write();
487 blender::MutableSpan<int> corner_edges = result->corner_edges_for_write();
488
489 int defgrp_index;
490 const MDeformVert *dvert;
491
492 blender::Array<blender::float3> corner_normals;
493
494 bke::MutableAttributeAccessor attributes = result->attributes_for_write();
496 "sharp_edge", bke::AttrDomain::Edge);
497
499 "custom_normal", bke::AttrDomain::Corner);
500 if (!custom_nors_dst) {
501 return result;
502 }
503 if (use_current_clnors) {
504 corner_normals.reinitialize(corner_verts.size());
505 const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
507 faces,
508 corner_verts,
509 corner_edges,
510 result->vert_to_face_map(),
511 result->face_normals_true(),
512 sharp_edges.span,
513 sharp_faces,
514 custom_nors_dst.span,
515 nullptr,
516 corner_normals);
517 }
518
519 MOD_get_vgroup(ob, result, enmd->defgrp_name, &dvert, &defgrp_index);
520
521 if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
523 ctx,
524 ob,
525 result,
526 custom_nors_dst.span,
527 corner_normals,
528 enmd->mix_mode,
529 enmd->mix_factor,
530 enmd->mix_limit,
531 dvert,
532 defgrp_index,
533 use_invert_vgroup,
534 positions,
535 sharp_edges.span,
536 corner_verts,
537 corner_edges,
538 faces);
539 }
540 else if (enmd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) {
542 ctx,
543 ob,
544 result,
545 custom_nors_dst.span,
546 corner_normals,
547 enmd->mix_mode,
548 enmd->mix_factor,
549 enmd->mix_limit,
550 dvert,
551 defgrp_index,
552 use_invert_vgroup,
553 positions,
554 sharp_edges.span,
555 corner_verts,
556 corner_edges,
557 faces);
558 }
559
560 result->runtime->is_original_bmesh = false;
561
562 custom_nors_dst.finish();
563 sharp_edges.finish();
564
565 return result;
566}
567
576
577static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
578{
580
581 /* Ask for vertex-groups if we need them. */
582 if (enmd->defgrp_name[0] != '\0') {
583 r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
584 }
585}
586
587static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
588{
590
591 walk(user_data, ob, (ID **)&enmd->target, IDWALK_CB_NOP);
592}
593
594static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
595{
597
598 return !is_valid_target(enmd);
599}
600
602{
604 if (enmd->target) {
605 DEG_add_object_relation(ctx->node, enmd->target, DEG_OB_COMP_TRANSFORM, "NormalEdit Modifier");
606 DEG_add_depends_on_transform_relation(ctx->node, "NormalEdit Modifier");
607 }
608}
609
610static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
611{
612 return normalEditModifier_do((NormalEditModifierData *)md, ctx, ctx->object, mesh);
613}
614
615static void panel_draw(const bContext * /*C*/, Panel *panel)
616{
617 uiLayout *col;
618 uiLayout *layout = panel->layout;
619
620 PointerRNA ob_ptr;
622
623 int mode = RNA_enum_get(ptr, "mode");
624
625 layout->prop(ptr, "mode", UI_ITEM_R_EXPAND, std::nullopt, ICON_NONE);
626
627 uiLayoutSetPropSep(layout, true);
628
629 layout->prop(ptr, "target", UI_ITEM_NONE, std::nullopt, ICON_NONE);
630
631 col = &layout->column(false);
633 col->prop(ptr, "use_direction_parallel", UI_ITEM_NONE, std::nullopt, ICON_NONE);
634
636}
637
638/* This panel could be open by default, but it isn't currently. */
639static void mix_mode_panel_draw(const bContext * /*C*/, Panel *panel)
640{
641 uiLayout *row;
642 uiLayout *layout = panel->layout;
643
644 PointerRNA ob_ptr;
646
647 uiLayoutSetPropSep(layout, true);
648
649 layout->prop(ptr, "mix_mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
650 layout->prop(ptr, "mix_factor", UI_ITEM_NONE, std::nullopt, ICON_NONE);
651
652 modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", std::nullopt);
653
654 row = &layout->row(true);
655 row->prop(ptr, "mix_limit", UI_ITEM_NONE, std::nullopt, ICON_NONE);
656 row->prop(ptr,
657 "no_polynors_fix",
659 "",
660 (RNA_boolean_get(ptr, "no_polynors_fix") ? ICON_LOCKED : ICON_UNLOCKED));
661}
662
663static void offset_panel_draw(const bContext * /*C*/, Panel *panel)
664{
665 uiLayout *layout = panel->layout;
666
668
669 int mode = RNA_enum_get(ptr, "mode");
670 PointerRNA target_ptr = RNA_pointer_get(ptr, "target");
671 bool needs_object_offset = (mode == MOD_NORMALEDIT_MODE_RADIAL &&
672 RNA_pointer_is_null(&target_ptr)) ||
674 RNA_boolean_get(ptr, "use_direction_parallel"));
675
676 uiLayoutSetPropSep(layout, true);
677
678 uiLayoutSetActive(layout, needs_object_offset);
679 layout->prop(ptr, "offset", UI_ITEM_NONE, std::nullopt, ICON_NONE);
680}
681
682static void panel_register(ARegionType *region_type)
683{
686 modifier_subpanel_register(region_type, "mix", "Mix", nullptr, mix_mode_panel_draw, panel_type);
688 region_type, "offset", "Offset", nullptr, offset_panel_draw, panel_type);
689}
690
692 /*idname*/ "NormalEdit",
693 /*name*/ N_("NormalEdit"),
694 /*struct_name*/ "NormalEditModifierData",
695 /*struct_size*/ sizeof(NormalEditModifierData),
696 /*srna*/ &RNA_NormalEditModifier,
700 /*icon*/ ICON_MOD_NORMALEDIT,
701
702 /*copy_data*/ BKE_modifier_copydata_generic,
703
704 /*deform_verts*/ nullptr,
705 /*deform_matrices*/ nullptr,
706 /*deform_verts_EM*/ nullptr,
707 /*deform_matrices_EM*/ nullptr,
708 /*modify_mesh*/ modify_mesh,
709 /*modify_geometry_set*/ nullptr,
710
711 /*init_data*/ init_data,
712 /*required_data_mask*/ required_data_mask,
713 /*free_data*/ nullptr,
714 /*is_disabled*/ is_disabled,
715 /*update_depsgraph*/ update_depsgraph,
716 /*depends_on_time*/ nullptr,
717 /*depends_on_normals*/ nullptr,
718 /*foreach_ID_link*/ foreach_ID_link,
719 /*foreach_tex_link*/ nullptr,
720 /*free_runtime_data*/ nullptr,
721 /*panel_register*/ panel_register,
722 /*blend_write*/ nullptr,
723 /*blend_read*/ nullptr,
724 /*foreach_cache*/ nullptr,
725};
support for deformation groups and hooks.
void BKE_defvert_extract_vgroup_to_loopweights(const MDeformVert *dvert, int defgroup, int verts_num, const int *corner_verts, int loops_num, bool invert_vgroup, float *r_weights)
Definition deform.cc:1125
@ LIB_ID_COPY_LOCALIZE
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:767
@ IDWALK_CB_NOP
void(*)(void *user_data, Object *ob, ID **idpoin, LibraryForeachIDCallbackFlag cb_flag) IDWalkFunc
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_SupportsMapping
@ eModifierTypeFlag_EnableInEditmode
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsMesh
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition BLI_bitmap.h:37
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition BLI_bitmap.h:61
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition BLI_bitmap.h:78
unsigned int BLI_bitmap
Definition BLI_bitmap.h:13
MINLINE float min_ff(float a, float b)
#define M_PI
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
float angle_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
MINLINE void mul_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3(float r[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 negate_v3_v3(float r[3], const float a[3])
void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], float t)
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void negate_v3(float r[3])
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
#define INIT_MINMAX(min, max)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define CLAMP_MIN(a, b)
void DEG_add_depends_on_transform_relation(DepsNodeHandle *node_handle, const char *description)
void DEG_add_object_relation(DepsNodeHandle *node_handle, Object *object, eDepsObjectComponentType component, const char *description)
@ DEG_OB_COMP_TRANSFORM
#define DNA_struct_default_get(struct_name)
@ MOD_NORMALEDIT_NO_POLYNORS_FIX
@ MOD_NORMALEDIT_INVERT_VGROUP
@ MOD_NORMALEDIT_USE_DIRECTION_PARALLEL
@ MOD_NORMALEDIT_MODE_RADIAL
@ MOD_NORMALEDIT_MODE_DIRECTIONAL
@ eModifierType_NormalEdit
@ MOD_NORMALEDIT_MIX_COPY
@ MOD_NORMALEDIT_MIX_ADD
@ MOD_NORMALEDIT_MIX_SUB
@ MOD_NORMALEDIT_MIX_MUL
Object is a sort of wrapper for general info.
static bool is_disabled
Read Guarded memory(de)allocation.
static void init_data(ModifierData *md)
static void panel_register(ARegionType *region_type)
static void required_data_mask(ModifierData *, CustomData_MeshMasks *r_cddata_masks)
static void panel_draw(const bContext *, Panel *panel)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
Definition MOD_array.cc:862
static void init_data(ModifierData *md)
static void mix_mode_panel_draw(const bContext *, Panel *panel)
static bool is_valid_target(NormalEditModifierData *enmd)
static void panel_register(ARegionType *region_type)
static void normalEditModifier_do_directional(NormalEditModifierData *enmd, const ModifierEvalContext *, Object *ob, Mesh *mesh, blender::MutableSpan< blender::short2 > clnors, blender::MutableSpan< blender::float3 > corner_normals, const short mix_mode, const float mix_factor, const float mix_limit, const MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup, const blender::Span< blender::float3 > positions, blender::MutableSpan< bool > sharp_edges, blender::MutableSpan< int > corner_verts, blender::MutableSpan< int > corner_edges, const blender::OffsetIndices< int > faces)
static bool is_valid_target_with_error(const Object *ob, NormalEditModifierData *enmd)
ModifierTypeInfo modifierType_NormalEdit
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
static void generate_vert_coordinates(Mesh *mesh, Object *ob, Object *ob_center, const float offset[3], const int verts_num, float(*r_cos)[3], blender::float3 *r_size)
static Mesh * normalEditModifier_do(NormalEditModifierData *enmd, const ModifierEvalContext *ctx, Object *ob, Mesh *mesh)
static void faces_check_flip(Mesh &mesh, blender::MutableSpan< blender::float3 > nos, const blender::Span< blender::float3 > face_normals)
static void panel_draw(const bContext *, Panel *panel)
static void offset_panel_draw(const bContext *, Panel *panel)
static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
static void normalEditModifier_do_radial(NormalEditModifierData *enmd, const ModifierEvalContext *, Object *ob, Mesh *mesh, blender::MutableSpan< blender::short2 > clnors, blender::MutableSpan< blender::float3 > corner_normals, const short mix_mode, const float mix_factor, const float mix_limit, const MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup, blender::Span< blender::float3 > vert_positions, blender::MutableSpan< bool > sharp_edges, blender::MutableSpan< int > corner_verts, blender::MutableSpan< int > corner_edges, const blender::OffsetIndices< int > faces)
static void mix_normals(const float mix_factor, const MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup, const float mix_limit, const short mix_mode, const int verts_num, const blender::Span< int > corner_verts, blender::float3 *nos_old, blender::float3 *nos_new)
void modifier_vgroup_ui(uiLayout *layout, PointerRNA *ptr, PointerRNA *ob_ptr, const StringRefNull vgroup_prop, const std::optional< StringRefNull > invert_vgroup_prop, const std::optional< StringRefNull > text)
PanelType * modifier_subpanel_register(ARegionType *region_type, const char *name, const char *label, PanelDrawFn draw_header, PanelDrawFn draw, PanelType *parent)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_error_message_draw(uiLayout *layout, PointerRNA *ptr)
void MOD_get_vgroup(const Object *ob, const Mesh *mesh, const char *name, const MDeformVert **dvert, int *defgrp_index)
Definition MOD_util.cc:156
@ UI_ITEM_R_EXPAND
void uiLayoutSetActive(uiLayout *layout, bool active)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
AttributeSet attributes
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
const T * data() const
Definition BLI_array.hh:301
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:398
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:573
constexpr bool is_empty() const
Definition BLI_span.hh:509
constexpr T * data() const
Definition BLI_span.hh:539
constexpr void reverse() const
Definition BLI_span.hh:650
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr const T * data() const
Definition BLI_span.hh:215
constexpr int64_t size() const
Definition BLI_span.hh:252
GAttributeReader lookup(const StringRef attribute_id) const
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt)
Definition frames.inl:1166
uint col
VecBase< short, 2 > short2
#define cos
VecBase< float, 3 > float3
#define CD_MASK_MDEFORMVERT
#define MEM_SAFE_FREE(v)
static void update_depsgraph(tGraphSliderOp *gso)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static char faces[256]
void normals_calc_corners(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, Span< int > corner_edges, GroupedSpan< int > vert_to_face_map, Span< float3 > face_normals, Span< bool > sharp_edges, Span< bool > sharp_faces, Span< short2 > custom_normals, CornerNormalSpaceArray *r_fan_spaces, MutableSpan< float3 > r_corner_normals)
void normals_corner_custom_set(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, Span< int > corner_edges, GroupedSpan< int > vert_to_face_map, Span< float3 > vert_normals, Span< float3 > face_normals, Span< bool > sharp_faces, MutableSpan< bool > sharp_edges, MutableSpan< float3 > r_custom_corner_normals, MutableSpan< short2 > r_clnors_data)
void mesh_flip_faces(Mesh &mesh, const IndexMask &selection)
T abs(const T &a)
VecBase< float, 3 > float3
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
bool RNA_pointer_is_null(const PointerRNA *ptr)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition DNA_ID.h:404
int corners_num
int verts_num
float scale[3]
struct uiLayout * layout
uiLayout & column(bool align)
uiLayout & row(bool align)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4227