Blender V5.0
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
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 dvert, defgrp_index, verts_num, corner_verts, use_invert_vgroup, facs);
140 }
141
142 for (i = corner_verts.size(), no_new = nos_new, no_old = nos_old, wfac = facs; i--;
143 no_new++, no_old++, wfac++)
144 {
145 const float fac = facs ? *wfac * mix_factor : mix_factor;
146
147 switch (mix_mode) {
149 add_v3_v3(*no_new, *no_old);
150 normalize_v3(*no_new);
151 break;
153 sub_v3_v3(*no_new, *no_old);
154 normalize_v3(*no_new);
155 break;
157 mul_v3_v3(*no_new, *no_old);
158 normalize_v3(*no_new);
159 break;
161 break;
162 }
163
165 *no_new,
166 *no_old,
167 *no_new,
168 (mix_limit < float(M_PI)) ? min_ff(fac, mix_limit / angle_v3v3(*no_new, *no_old)) : fac);
169 }
170
171 MEM_SAFE_FREE(facs);
172}
173
174/* Check face normals and new loop normals are compatible, otherwise flip faces
175 * (and invert matching face normals). */
176static void faces_check_flip(Mesh &mesh,
178 const blender::Span<blender::float3> face_normals)
179{
180 using namespace blender;
181 const OffsetIndices faces = mesh.faces();
182 IndexMaskMemory memory;
183 const IndexMask faces_to_flip = IndexMask::from_predicate(
184 faces.index_range(), GrainSize(1024), memory, [&](const int i) {
185 const blender::IndexRange face = faces[i];
186 float norsum[3] = {0.0f};
187
188 for (const int64_t j : face) {
189 add_v3_v3(norsum, nos[j]);
190 }
191 if (!normalize_v3(norsum)) {
192 return false;
193 }
194
195 /* If average of new loop normals is opposed to face normal, flip face. */
196 if (dot_v3v3(face_normals[i], norsum) < 0.0f) {
197 nos.slice(faces[i].drop_front(1)).reverse();
198 return true;
199 }
200 return false;
201 });
202
203 bke::mesh_flip_faces(mesh, faces_to_flip);
204}
205
207 const ModifierEvalContext * /*ctx*/,
208 Object *ob,
209 Mesh *mesh,
212 const short mix_mode,
213 const float mix_factor,
214 const float mix_limit,
215 const MDeformVert *dvert,
216 const int defgrp_index,
217 const bool use_invert_vgroup,
218 blender::Span<blender::float3> vert_positions,
219 blender::MutableSpan<bool> sharp_edges,
220 blender::MutableSpan<int> corner_verts,
221 blender::MutableSpan<int> corner_edges,
223{
224 using namespace blender;
225 Object *ob_target = enmd->target;
226
227 const bool do_facenors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0;
228
229 float (*cos)[3] = MEM_malloc_arrayN<float[3]>(size_t(vert_positions.size()), __func__);
230 blender::Array<blender::float3> nos(corner_verts.size());
231 float3 size;
232
233 BLI_bitmap *done_verts = BLI_BITMAP_NEW(size_t(vert_positions.size()), __func__);
234
235 generate_vert_coordinates(mesh, ob, ob_target, enmd->offset, vert_positions.size(), cos, &size);
236
268 {
269 const float a = size[0], b = size[1], c = size[2];
270 const float m2 = (b * b) / (a * a);
271 const float n2 = (c * c) / (a * a);
272
273 /* We reuse cos to now store the ellipsoid-normal of the verts! */
274 for (const int64_t i : corner_verts.index_range()) {
275 const int vidx = corner_verts[i];
276 float *co = cos[vidx];
277
278 if (!BLI_BITMAP_TEST(done_verts, vidx)) {
279 const float x2 = co[0] * co[0];
280 const float y2 = co[1] * co[1];
281 const float z2 = co[2] * co[2];
282 const float a2 = x2 + (y2 / m2) + (z2 / n2);
283 const float b2 = (m2 * x2) + y2 + (m2 * z2 / n2);
284 const float c2 = (n2 * x2) + (n2 * y2 / m2) + z2;
285
286 co[0] /= a2;
287 co[1] /= b2;
288 co[2] /= c2;
289 normalize_v3(co);
290
291 BLI_BITMAP_ENABLE(done_verts, vidx);
292 }
293 nos[i] = co;
294 }
295 }
296
297 if (!corner_normals.is_empty()) {
298 mix_normals(mix_factor,
299 dvert,
300 defgrp_index,
301 use_invert_vgroup,
302 mix_limit,
303 mix_mode,
304 vert_positions.size(),
305 corner_verts,
306 corner_normals.data(),
307 nos.data());
308 }
309
310 if (do_facenors_fix) {
311 faces_check_flip(*mesh, nos, mesh->face_normals_true());
312 }
313 const bke::AttributeAccessor attributes = mesh->attributes();
314 const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
316 faces,
317 corner_verts,
318 corner_edges,
319 mesh->vert_to_face_map(),
320 mesh->vert_normals_true(),
321 mesh->face_normals_true(),
322 sharp_faces,
323 sharp_edges,
324 nos,
325 clnors);
326
327 MEM_freeN(cos);
328 MEM_freeN(done_verts);
329}
330
332 const ModifierEvalContext * /*ctx*/,
333 Object *ob,
334 Mesh *mesh,
337 const short mix_mode,
338 const float mix_factor,
339 const float mix_limit,
340 const MDeformVert *dvert,
341 const int defgrp_index,
342 const bool use_invert_vgroup,
343 const blender::Span<blender::float3> positions,
344 blender::MutableSpan<bool> sharp_edges,
345 blender::MutableSpan<int> corner_verts,
346 blender::MutableSpan<int> corner_edges,
348{
349 using namespace blender;
350 Object *ob_target = enmd->target;
351
352 const bool do_facenors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0;
353 const bool use_parallel_normals = (enmd->flag & MOD_NORMALEDIT_USE_DIRECTION_PARALLEL) != 0;
354
355 blender::Array<blender::float3> nos(corner_verts.size());
356
357 float target_co[3];
358 int i;
359
360 /* Get target's center coordinates in ob local coordinates. */
361 float mat[4][4];
362
363 invert_m4_m4(mat, ob->object_to_world().ptr());
364 mul_m4_m4m4(mat, mat, ob_target->object_to_world().ptr());
365 copy_v3_v3(target_co, mat[3]);
366
367 if (use_parallel_normals) {
368 float no[3];
369
370 sub_v3_v3v3(no, target_co, enmd->offset);
371 normalize_v3(no);
372
373 for (i = corner_verts.size(); i--;) {
374 copy_v3_v3(nos[i], no);
375 }
376 }
377 else {
378 float (*cos)[3] = MEM_malloc_arrayN<float[3]>(size_t(positions.size()), __func__);
379 generate_vert_coordinates(mesh, ob, ob_target, nullptr, positions.size(), cos, nullptr);
380
381 BLI_bitmap *done_verts = BLI_BITMAP_NEW(size_t(positions.size()), __func__);
382
383 /* We reuse cos to now store the 'to target' normal of the verts! */
384 for (const int64_t i : corner_verts.index_range()) {
385 const int vidx = corner_verts[i];
386 float *co = cos[vidx];
387
388 if (!BLI_BITMAP_TEST(done_verts, vidx)) {
389 sub_v3_v3v3(co, target_co, co);
390 normalize_v3(co);
391
392 BLI_BITMAP_ENABLE(done_verts, vidx);
393 }
394 nos[i] = co;
395 }
396
397 MEM_freeN(done_verts);
398 MEM_freeN(cos);
399 }
400
401 if (!corner_normals.is_empty()) {
402 mix_normals(mix_factor,
403 dvert,
404 defgrp_index,
405 use_invert_vgroup,
406 mix_limit,
407 mix_mode,
408 positions.size(),
409 corner_verts,
410 corner_normals.data(),
411 nos.data());
412 }
413
414 if (do_facenors_fix) {
415 faces_check_flip(*mesh, nos, mesh->face_normals_true());
416 }
417 const bke::AttributeAccessor attributes = mesh->attributes();
418 const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
420 faces,
421 corner_verts,
422 corner_edges,
423 mesh->vert_to_face_map(),
424 mesh->vert_normals_true(),
425 mesh->face_normals_true(),
426 sharp_faces,
427 sharp_edges,
428 nos,
429 clnors);
430}
431
433{
434 if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
435 return true;
436 }
437 if ((enmd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) && enmd->target) {
438 return true;
439 }
440 return false;
441}
442
444{
445 if (is_valid_target(enmd)) {
446 return true;
447 }
448 BKE_modifier_set_error(ob, (ModifierData *)enmd, "Invalid target settings");
449 return false;
450}
451
453 const ModifierEvalContext *ctx,
454 Object *ob,
455 Mesh *mesh)
456{
457 using namespace blender;
458 const bool use_invert_vgroup = ((enmd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0);
459 const bool use_current_clnors = !((enmd->mix_mode == MOD_NORMALEDIT_MIX_COPY) &&
460 (enmd->mix_factor == 1.0f) && (enmd->defgrp_name[0] == '\0') &&
461 (enmd->mix_limit == float(M_PI)));
462
463 /* Do not run that modifier at all if auto-smooth is disabled! */
464 if (!is_valid_target_with_error(ctx->object, enmd) || mesh->corners_num == 0) {
465 return mesh;
466 }
467
468 Mesh *result;
469 if (mesh->edges().data() == ((Mesh *)ob->data)->edges().data()) {
470 /* We need to duplicate data here, otherwise setting custom normals
471 * (which may also affect sharp edges) could
472 * modify original mesh, see #43671. */
473 result = (Mesh *)BKE_id_copy_ex(nullptr, &mesh->id, nullptr, LIB_ID_COPY_LOCALIZE);
474 }
475 else {
476 result = mesh;
477 }
478
479 const blender::Span<blender::float3> positions = result->vert_positions();
480 const OffsetIndices faces = result->faces();
481 blender::MutableSpan<int> corner_verts = result->corner_verts_for_write();
482 blender::MutableSpan<int> corner_edges = result->corner_edges_for_write();
483
484 int defgrp_index;
485 const MDeformVert *dvert;
486
487 blender::Array<blender::float3> corner_normals;
488
489 bke::MutableAttributeAccessor attributes = result->attributes_for_write();
491 "sharp_edge", bke::AttrDomain::Edge);
492
494 "custom_normal", bke::AttrDomain::Corner);
495 if (!custom_nors_dst) {
496 return result;
497 }
498 if (use_current_clnors) {
499 corner_normals.reinitialize(corner_verts.size());
500 const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
502 faces,
503 corner_verts,
504 corner_edges,
505 result->vert_to_face_map(),
506 result->face_normals_true(),
507 sharp_edges.span,
508 sharp_faces,
509 custom_nors_dst.span,
510 nullptr,
511 corner_normals);
512 }
513
514 MOD_get_vgroup(ob, result, enmd->defgrp_name, &dvert, &defgrp_index);
515
516 if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
518 ctx,
519 ob,
520 result,
521 custom_nors_dst.span,
522 corner_normals,
523 enmd->mix_mode,
524 enmd->mix_factor,
525 enmd->mix_limit,
526 dvert,
527 defgrp_index,
528 use_invert_vgroup,
529 positions,
530 sharp_edges.span,
531 corner_verts,
532 corner_edges,
533 faces);
534 }
535 else if (enmd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) {
537 ctx,
538 ob,
539 result,
540 custom_nors_dst.span,
541 corner_normals,
542 enmd->mix_mode,
543 enmd->mix_factor,
544 enmd->mix_limit,
545 dvert,
546 defgrp_index,
547 use_invert_vgroup,
548 positions,
549 sharp_edges.span,
550 corner_verts,
551 corner_edges,
552 faces);
553 }
554
555 result->runtime->is_original_bmesh = false;
556
557 custom_nors_dst.finish();
558 sharp_edges.finish();
559
560 return result;
561}
562
571
572static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
573{
575
576 /* Ask for vertex-groups if we need them. */
577 if (enmd->defgrp_name[0] != '\0') {
578 r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
579 }
580}
581
582static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
583{
585
586 walk(user_data, ob, (ID **)&enmd->target, IDWALK_CB_NOP);
587}
588
589static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
590{
592
593 return !is_valid_target(enmd);
594}
595
597{
599 if (enmd->target) {
600 DEG_add_object_relation(ctx->node, enmd->target, DEG_OB_COMP_TRANSFORM, "NormalEdit Modifier");
601 DEG_add_depends_on_transform_relation(ctx->node, "NormalEdit Modifier");
602 }
603}
604
605static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
606{
607 return normalEditModifier_do((NormalEditModifierData *)md, ctx, ctx->object, mesh);
608}
609
610static void panel_draw(const bContext * /*C*/, Panel *panel)
611{
612 uiLayout *col;
613 uiLayout *layout = panel->layout;
614
615 PointerRNA ob_ptr;
617
618 int mode = RNA_enum_get(ptr, "mode");
619
620 layout->prop(ptr, "mode", UI_ITEM_R_EXPAND, std::nullopt, ICON_NONE);
621
622 layout->use_property_split_set(true);
623
624 layout->prop(ptr, "target", UI_ITEM_NONE, std::nullopt, ICON_NONE);
625
626 col = &layout->column(false);
627 col->active_set(mode == MOD_NORMALEDIT_MODE_DIRECTIONAL);
628 col->prop(ptr, "use_direction_parallel", UI_ITEM_NONE, std::nullopt, ICON_NONE);
629
631}
632
633/* This panel could be open by default, but it isn't currently. */
634static void mix_mode_panel_draw(const bContext * /*C*/, Panel *panel)
635{
636 uiLayout *row;
637 uiLayout *layout = panel->layout;
638
639 PointerRNA ob_ptr;
641
642 layout->use_property_split_set(true);
643
644 layout->prop(ptr, "mix_mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
645 layout->prop(ptr, "mix_factor", UI_ITEM_NONE, std::nullopt, ICON_NONE);
646
647 modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", std::nullopt);
648
649 row = &layout->row(true);
650 row->prop(ptr, "mix_limit", UI_ITEM_NONE, std::nullopt, ICON_NONE);
651 row->prop(ptr,
652 "no_polynors_fix",
654 "",
655 (RNA_boolean_get(ptr, "no_polynors_fix") ? ICON_LOCKED : ICON_UNLOCKED));
656}
657
658static void offset_panel_draw(const bContext * /*C*/, Panel *panel)
659{
660 uiLayout *layout = panel->layout;
661
663
664 int mode = RNA_enum_get(ptr, "mode");
665 PointerRNA target_ptr = RNA_pointer_get(ptr, "target");
666 bool needs_object_offset = (mode == MOD_NORMALEDIT_MODE_RADIAL &&
667 RNA_pointer_is_null(&target_ptr)) ||
669 RNA_boolean_get(ptr, "use_direction_parallel"));
670
671 layout->use_property_split_set(true);
672
673 layout->active_set(needs_object_offset);
674 layout->prop(ptr, "offset", UI_ITEM_NONE, std::nullopt, ICON_NONE);
675}
676
677static void panel_register(ARegionType *region_type)
678{
681 modifier_subpanel_register(region_type, "mix", "Mix", nullptr, mix_mode_panel_draw, panel_type);
683 region_type, "offset", "Offset", nullptr, offset_panel_draw, panel_type);
684}
685
687 /*idname*/ "NormalEdit",
688 /*name*/ N_("NormalEdit"),
689 /*struct_name*/ "NormalEditModifierData",
690 /*struct_size*/ sizeof(NormalEditModifierData),
691 /*srna*/ &RNA_NormalEditModifier,
695 /*icon*/ ICON_MOD_NORMALEDIT,
696
697 /*copy_data*/ BKE_modifier_copydata_generic,
698
699 /*deform_verts*/ nullptr,
700 /*deform_matrices*/ nullptr,
701 /*deform_verts_EM*/ nullptr,
702 /*deform_matrices_EM*/ nullptr,
703 /*modify_mesh*/ modify_mesh,
704 /*modify_geometry_set*/ nullptr,
705
706 /*init_data*/ init_data,
707 /*required_data_mask*/ required_data_mask,
708 /*free_data*/ nullptr,
709 /*is_disabled*/ is_disabled,
710 /*update_depsgraph*/ update_depsgraph,
711 /*depends_on_time*/ nullptr,
712 /*depends_on_normals*/ nullptr,
713 /*foreach_ID_link*/ foreach_ID_link,
714 /*foreach_tex_link*/ nullptr,
715 /*free_runtime_data*/ nullptr,
716 /*panel_register*/ panel_register,
717 /*blend_write*/ nullptr,
718 /*blend_read*/ nullptr,
719 /*foreach_cache*/ nullptr,
720 /*foreach_working_space_color*/ nullptr,
721};
support for deformation groups and hooks.
void BKE_defvert_extract_vgroup_to_loopweights(const MDeformVert *dvert, int defgroup, int verts_num, blender::Span< int > corner_verts, bool invert_vgroup, float *r_weights)
Definition deform.cc:1135
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:777
@ LIB_ID_COPY_LOCALIZE
@ 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 CD_MASK_MDEFORMVERT
#define DNA_struct_default_get(struct_name)
@ MOD_NORMALEDIT_MODE_RADIAL
@ MOD_NORMALEDIT_MODE_DIRECTIONAL
@ eModifierType_NormalEdit
@ MOD_NORMALEDIT_NO_POLYNORS_FIX
@ MOD_NORMALEDIT_INVERT_VGROUP
@ MOD_NORMALEDIT_USE_DIRECTION_PARALLEL
@ 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.
#define MEM_SAFE_FREE(v)
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
#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:312
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:419
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 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, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
nullptr float
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt)
Definition frames.inl:1166
uint col
#define cos
VecBase< short, 2 > short2
VecBase< float, 3 > float3
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:414
int corners_num
int verts_num
float scale[3]
struct uiLayout * layout
uiLayout & column(bool align)
void active_set(bool active)
uiLayout & row(bool align)
void use_property_split_set(bool value)
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:4238