Blender V4.3
MOD_weighted_normal.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
9#include "MEM_guardedalloc.h"
10
11#include "BLI_array_utils.hh"
12#include "BLI_bitmap.h"
13#include "BLI_linklist.h"
14#include "BLI_math_vector.h"
15
16#include "BLT_translation.hh"
17
18#include "DNA_defaults.h"
19#include "DNA_mesh_types.h"
20#include "DNA_meshdata_types.h"
21#include "DNA_object_types.h"
22#include "DNA_scene_types.h"
23#include "DNA_screen_types.h"
24
25#include "BKE_attribute.hh"
26#include "BKE_context.hh"
27#include "BKE_deform.hh"
28#include "BKE_lib_id.hh"
29#include "BKE_mesh.hh"
30#include "BKE_mesh_mapping.hh"
31#include "BKE_screen.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_modifiertypes.hh"
40#include "MOD_ui_common.hh"
41#include "MOD_util.hh"
42
43#include "bmesh.hh"
44
45#define CLNORS_VALID_VEC_LEN (1e-6f)
46
47struct ModePair {
48 float val; /* Contains mode based value (face area / corner angle). */
49 int index; /* Index value per face or per loop. */
50};
51
52/* Sorting function used in modifier, sorts in decreasing order. */
53static int modepair_cmp_by_val_inverse(const void *p1, const void *p2)
54{
55 ModePair *r1 = (ModePair *)p1;
56 ModePair *r2 = (ModePair *)p2;
57
58 return (r1->val < r2->val) ? 1 : ((r1->val > r2->val) ? -1 : 0);
59}
60
61/* There will be one of those per vertex
62 * (simple case, computing one normal per vertex), or per smooth fan. */
64 float normal[3];
65
66 int loops_num; /* Count number of loops using this item so far. */
67 float curr_val; /* Current max val for this item. */
68 int curr_strength; /* Current max strength encountered for this item. */
69};
70
71#define NUM_CACHED_INVERSE_POWERS_OF_WEIGHT 128
72
106
113 const int face_index)
114{
115 BLI_assert(wn_data->face_strength != nullptr);
116
117 const int mp_strength = wn_data->face_strength[face_index];
118
119 if (mp_strength > item_data->curr_strength) {
120 item_data->curr_strength = mp_strength;
121 item_data->curr_val = 0.0f;
122 item_data->loops_num = 0;
123 zero_v3(item_data->normal);
124 }
125
126 return mp_strength == item_data->curr_strength;
127}
128
130 WeightedNormalData *wn_data,
132 const int mv_index,
133 const int face_index,
134 const float curr_val,
135 const bool use_face_influence)
136{
137 const blender::Span<blender::float3> face_normals = wn_data->face_normals;
138
139 const MDeformVert *dvert = wn_data->dvert;
140 const int defgrp_index = wn_data->defgrp_index;
141 const bool use_invert_vgroup = wn_data->use_invert_vgroup;
142
143 const float weight = wn_data->weight;
144
145 float *cached_inverse_powers_of_weight = wn_data->cached_inverse_powers_of_weight;
146
147 const bool has_vgroup = dvert != nullptr;
148 const bool vert_of_group = has_vgroup &&
149 BKE_defvert_find_index(&dvert[mv_index], defgrp_index) != nullptr;
150
151 if (has_vgroup &&
152 ((vert_of_group && use_invert_vgroup) || (!vert_of_group && !use_invert_vgroup)))
153 {
154 return;
155 }
156
157 if (use_face_influence && !check_item_face_strength(wn_data, item_data, face_index)) {
158 return;
159 }
160
161 /* If item's curr_val is 0 init it to present value. */
162 if (item_data->curr_val == 0.0f) {
163 item_data->curr_val = curr_val;
164 }
165 if (!compare_ff(item_data->curr_val, curr_val, wnmd->thresh)) {
166 /* item's curr_val and present value differ more than threshold, update. */
167 item_data->loops_num++;
168 item_data->curr_val = curr_val;
169 }
170
171 /* Exponentially divided weight for each normal
172 * (since a few values will be used by most cases, we cache those). */
173 const int loops_num = item_data->loops_num;
174 if (loops_num < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT &&
175 cached_inverse_powers_of_weight[loops_num] == 0.0f)
176 {
177 cached_inverse_powers_of_weight[loops_num] = 1.0f / powf(weight, loops_num);
178 }
179 const float inverted_n_weight = loops_num < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT ?
180 cached_inverse_powers_of_weight[loops_num] :
181 1.0f / powf(weight, loops_num);
182
183 madd_v3_v3fl(item_data->normal, face_normals[face_index], curr_val * inverted_n_weight);
184}
185
187 WeightedNormalData *wn_data)
188{
189 using namespace blender;
190 const int verts_num = wn_data->verts_num;
191
192 const blender::Span<blender::float3> positions = wn_data->vert_positions;
193 const blender::Span<int2> edges = wn_data->edges;
194 const blender::OffsetIndices faces = wn_data->faces;
195 const blender::Span<int> corner_verts = wn_data->corner_verts;
196 const blender::Span<int> corner_edges = wn_data->corner_edges;
197
198 MutableSpan<short2> clnors = wn_data->clnors;
199 const blender::Span<int> loop_to_face = wn_data->loop_to_face;
200
201 const blender::Span<blender::float3> face_normals = wn_data->face_normals;
202 const int *face_strength = wn_data->face_strength;
203
204 const MDeformVert *dvert = wn_data->dvert;
205
206 const short mode = wn_data->mode;
207 ModePair *mode_pair = wn_data->mode_pair;
208
209 const bool has_clnors = wn_data->has_clnors;
211
212 const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0;
213 const bool use_face_influence = (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) != 0 &&
214 face_strength != nullptr;
215 const bool has_vgroup = dvert != nullptr;
216
217 blender::Array<blender::float3> corner_normals;
218
220 if (keep_sharp) {
221 /* This will give us loop normal spaces,
222 * we do not actually care about computed corner_normals for now... */
223 corner_normals.reinitialize(corner_verts.size());
224 bke::mesh::normals_calc_corners(positions,
225 edges,
226 faces,
227 corner_verts,
228 corner_edges,
229 loop_to_face,
230 wn_data->vert_normals,
231 wn_data->face_normals,
232 wn_data->sharp_edges,
233 wn_data->sharp_faces,
234 has_clnors ? clnors.data() : nullptr,
235 &lnors_spacearr,
236 corner_normals);
237
240 items_data = Array<WeightedNormalDataAggregateItem>(lnors_spacearr.spaces.size(), start_item);
241 }
242 else {
245 items_data = Array<WeightedNormalDataAggregateItem>(verts_num, start_item);
246 lnors_spacearr.corner_space_indices.reinitialize(corner_verts.size());
247 array_utils::fill_index_range<int>(lnors_spacearr.corner_space_indices);
248 }
249 wn_data->items_data = items_data;
250
251 switch (mode) {
253 for (const int i : faces.index_range()) {
254 const int face_index = mode_pair[i].index;
255 const float mp_val = mode_pair[i].val;
256
257 for (const int corner : faces[face_index]) {
258 const int mv_index = corner_verts[corner];
259 const int space_index = lnors_spacearr.corner_space_indices[corner];
260
261 WeightedNormalDataAggregateItem *item_data = keep_sharp ? &items_data[space_index] :
262 &items_data[mv_index];
263
265 wnmd, wn_data, item_data, mv_index, face_index, mp_val, use_face_influence);
266 }
267 }
268 break;
271 for (int i = 0; i < corner_verts.size(); i++) {
272 const int corner = mode_pair[i].index;
273 const float ml_val = mode_pair[i].val;
274 const int space_index = lnors_spacearr.corner_space_indices[corner];
275
276 const int face_index = loop_to_face[corner];
277 const int mv_index = corner_verts[corner];
278 WeightedNormalDataAggregateItem *item_data = keep_sharp ? &items_data[space_index] :
279 &items_data[mv_index];
280
282 wnmd, wn_data, item_data, mv_index, face_index, ml_val, use_face_influence);
283 }
284 break;
285 default:
287 }
288
289 /* Validate computed weighted normals. */
290 for (int item_index : items_data.index_range()) {
291 if (normalize_v3(items_data[item_index].normal) < CLNORS_VALID_VEC_LEN) {
292 zero_v3(items_data[item_index].normal);
293 }
294 }
295
296 if (keep_sharp) {
297 /* Set loop normals for normal computed for each lnor space (smooth fan).
298 * Note that corner_normals is already populated with clnors
299 * (before this modifier is applied, at start of this function),
300 * so no need to recompute them here. */
301 for (int corner = 0; corner < corner_verts.size(); corner++) {
302 const int space_index = lnors_spacearr.corner_space_indices[corner];
303 WeightedNormalDataAggregateItem *item_data = &items_data[space_index];
304 if (!is_zero_v3(item_data->normal)) {
305 copy_v3_v3(corner_normals[corner], item_data->normal);
306 }
307 }
308
310 edges,
311 faces,
312 corner_verts,
313 corner_edges,
314 wn_data->vert_normals,
315 face_normals,
316 wn_data->sharp_faces,
317 wn_data->sharp_edges,
318 corner_normals,
319 clnors);
320 }
321 else {
322 /* TODO: Ideally, we could add an option to `BKE_mesh_normals_loop_custom_[from_verts_]set()`
323 * to keep current clnors instead of resetting them to default auto-computed ones,
324 * when given new custom normal is zero-vec.
325 * But this is not exactly trivial change, better to keep this optimization for later...
326 */
327 if (!has_vgroup) {
328 /* NOTE: in theory, we could avoid this extra allocation & copying...
329 * But think we can live with it for now,
330 * and it makes code simpler & cleaner. */
331 blender::Array<blender::float3> vert_normals(verts_num, float3(0.0f));
332
333 for (int corner = 0; corner < corner_verts.size(); corner++) {
334 const int mv_index = corner_verts[corner];
335 copy_v3_v3(vert_normals[mv_index], items_data[mv_index].normal);
336 }
337
339 edges,
340 faces,
341 corner_verts,
342 corner_edges,
343 wn_data->vert_normals,
344 face_normals,
345 wn_data->sharp_faces,
346 wn_data->sharp_edges,
347 vert_normals,
348 clnors);
349 }
350 else {
351 corner_normals.reinitialize(corner_verts.size());
353 edges,
354 faces,
355 corner_verts,
356 corner_edges,
357 loop_to_face,
358 wn_data->vert_normals,
359 face_normals,
360 wn_data->sharp_edges,
361 wn_data->sharp_faces,
362 has_clnors ? clnors.data() : nullptr,
363 nullptr,
364 corner_normals);
365
366 for (int corner = 0; corner < corner_verts.size(); corner++) {
367 const int item_index = corner_verts[corner];
368 if (!is_zero_v3(items_data[item_index].normal)) {
369 copy_v3_v3(corner_normals[corner], items_data[item_index].normal);
370 }
371 }
373 edges,
374 faces,
375 corner_verts,
376 corner_edges,
377 wn_data->vert_normals,
378 face_normals,
379 wn_data->sharp_faces,
380 wn_data->sharp_edges,
381 corner_normals,
382 clnors);
383 }
384 }
385}
386
388{
389 const blender::Span<blender::float3> positions = wn_data->vert_positions;
390 const blender::OffsetIndices faces = wn_data->faces;
391 const blender::Span<int> corner_verts = wn_data->corner_verts;
392
393 ModePair *face_area = static_cast<ModePair *>(
394 MEM_malloc_arrayN(faces.size(), sizeof(*face_area), __func__));
395
396 ModePair *f_area = face_area;
397 for (const int i : faces.index_range()) {
398 f_area[i].val = blender::bke::mesh::face_area_calc(positions, corner_verts.slice(faces[i]));
399 f_area[i].index = i;
400 }
401
402 qsort(face_area, faces.size(), sizeof(*face_area), modepair_cmp_by_val_inverse);
403
404 wn_data->mode_pair = face_area;
405 apply_weights_vertex_normal(wnmd, wn_data);
406}
407
409{
410 const blender::Span<blender::float3> positions = wn_data->vert_positions;
411 const blender::OffsetIndices faces = wn_data->faces;
412 const blender::Span<int> corner_verts = wn_data->corner_verts;
413
414 ModePair *corner_angle = static_cast<ModePair *>(
415 MEM_malloc_arrayN(corner_verts.size(), sizeof(*corner_angle), __func__));
416
417 for (const int i : faces.index_range()) {
418 const blender::IndexRange face = faces[i];
419 float *index_angle = static_cast<float *>(
420 MEM_malloc_arrayN(face.size(), sizeof(*index_angle), __func__));
422 positions, corner_verts.slice(face), {index_angle, face.size()});
423
424 ModePair *c_angl = &corner_angle[face.start()];
425 float *angl = index_angle;
426 for (int corner = face.start(); corner < face.start() + face.size();
427 corner++, c_angl++, angl++)
428 {
429 c_angl->val = float(M_PI) - *angl;
430 c_angl->index = corner;
431 }
432 MEM_freeN(index_angle);
433 }
434
435 qsort(corner_angle, corner_verts.size(), sizeof(*corner_angle), modepair_cmp_by_val_inverse);
436
437 wn_data->mode_pair = corner_angle;
438 apply_weights_vertex_normal(wnmd, wn_data);
439}
440
442{
443 const blender::Span<blender::float3> positions = wn_data->vert_positions;
444 const blender::OffsetIndices faces = wn_data->faces;
445 const blender::Span<int> corner_verts = wn_data->corner_verts;
446
447 ModePair *combined = static_cast<ModePair *>(
448 MEM_malloc_arrayN(corner_verts.size(), sizeof(*combined), __func__));
449
450 for (const int i : faces.index_range()) {
451 const blender::IndexRange face = faces[i];
452 const blender::Span<int> face_verts = corner_verts.slice(face);
453 const float face_area = blender::bke::mesh::face_area_calc(positions, face_verts);
454 float *index_angle = static_cast<float *>(
455 MEM_malloc_arrayN(size_t(face.size()), sizeof(*index_angle), __func__));
456 blender::bke::mesh::face_angles_calc(positions, face_verts, {index_angle, face.size()});
457
458 ModePair *cmbnd = &combined[face.start()];
459 float *angl = index_angle;
460 for (int corner = face.start(); corner < face.start() + face.size(); corner++, cmbnd++, angl++)
461 {
462 /* In this case val is product of corner angle and face area. */
463 cmbnd->val = (float(M_PI) - *angl) * face_area;
464 cmbnd->index = corner;
465 }
466 MEM_freeN(index_angle);
467 }
468
469 qsort(combined, corner_verts.size(), sizeof(*combined), modepair_cmp_by_val_inverse);
470
471 wn_data->mode_pair = combined;
472 apply_weights_vertex_normal(wnmd, wn_data);
473}
474
475static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
476{
477 using namespace blender;
479
480 Mesh *result;
481 result = (Mesh *)BKE_id_copy_ex(nullptr, &mesh->id, nullptr, LIB_ID_COPY_LOCALIZE);
482
483 const int verts_num = result->verts_num;
484 const blender::Span<blender::float3> positions = mesh->vert_positions();
485 const blender::Span<int2> edges = mesh->edges();
486 const OffsetIndices faces = result->faces();
487 const blender::Span<int> corner_verts = mesh->corner_verts();
488 const blender::Span<int> corner_edges = mesh->corner_edges();
489
490 /* Right now:
491 * If weight = 50 then all faces are given equal weight.
492 * If weight > 50 then more weight given to faces with larger values (face area / corner angle).
493 * If weight < 50 then more weight given to faces with lesser values. However current calculation
494 * does not converge to min/max.
495 */
496 float weight = float(wnmd->weight) / 50.0f;
497 if (wnmd->weight == 100) {
498 weight = float(SHRT_MAX);
499 }
500 else if (wnmd->weight == 1) {
501 weight = 1 / float(SHRT_MAX);
502 }
503 else if ((weight - 1) * 25 > 1) {
504 weight = (weight - 1) * 25;
505 }
506
508 &result->corner_data, CD_CUSTOMLOOPNORMAL, mesh->corners_num));
509
510 /* Keep info whether we had clnors,
511 * it helps when generating clnor spaces and default normals. */
512 const bool has_clnors = clnors != nullptr;
513 if (!clnors) {
514 clnors = static_cast<blender::short2 *>(CustomData_add_layer(
515 &result->corner_data, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, corner_verts.size()));
516 }
517
518 const MDeformVert *dvert;
519 int defgrp_index;
520 MOD_get_vgroup(ctx->object, mesh, wnmd->defgrp_name, &dvert, &defgrp_index);
521
522 const Span<int> loop_to_face_map = result->corner_to_face_map();
523
524 bke::MutableAttributeAccessor attributes = result->attributes_for_write();
525 bke::SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
526 "sharp_edge", bke::AttrDomain::Edge);
527
528 WeightedNormalData wn_data{};
529 wn_data.verts_num = verts_num;
530
531 wn_data.vert_positions = positions;
532 wn_data.vert_normals = result->vert_normals();
533 wn_data.edges = edges;
534 wn_data.sharp_edges = sharp_edges.span;
535
536 wn_data.corner_verts = corner_verts;
537 wn_data.corner_edges = corner_edges;
538 wn_data.loop_to_face = loop_to_face_map;
539 wn_data.clnors = {clnors, mesh->corners_num};
540 wn_data.has_clnors = has_clnors;
541
542 wn_data.faces = faces;
543 wn_data.face_normals = mesh->face_normals();
544 wn_data.sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
545 wn_data.face_strength = static_cast<const int *>(CustomData_get_layer_named(
547
548 wn_data.dvert = dvert;
549 wn_data.defgrp_index = defgrp_index;
550 wn_data.use_invert_vgroup = (wnmd->flag & MOD_WEIGHTEDNORMAL_INVERT_VGROUP) != 0;
551
552 wn_data.weight = weight;
553 wn_data.mode = wnmd->mode;
554
555 switch (wnmd->mode) {
557 wn_face_area(wnmd, &wn_data);
558 break;
560 wn_corner_angle(wnmd, &wn_data);
561 break;
563 wn_face_with_angle(wnmd, &wn_data);
564 break;
565 }
566
567 MEM_SAFE_FREE(wn_data.mode_pair);
568
569 result->runtime->is_original_bmesh = false;
570
571 sharp_edges.finish();
572
573 return result;
574}
575
584
585static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
586{
588
589 r_cddata_masks->lmask = CD_MASK_CUSTOMLOOPNORMAL;
590
591 if (wnmd->defgrp_name[0] != '\0') {
592 r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
593 }
594
596 r_cddata_masks->pmask |= CD_MASK_PROP_INT32;
597 }
598}
599
600static void panel_draw(const bContext * /*C*/, Panel *panel)
601{
602 uiLayout *col;
603 uiLayout *layout = panel->layout;
604
605 PointerRNA ob_ptr;
607
608 uiLayoutSetPropSep(layout, true);
609
610 uiItemR(layout, ptr, "mode", UI_ITEM_NONE, nullptr, ICON_NONE);
611
612 uiItemR(layout, ptr, "weight", UI_ITEM_NONE, IFACE_("Weight"), ICON_NONE);
613 uiItemR(layout, ptr, "thresh", UI_ITEM_NONE, IFACE_("Threshold"), ICON_NONE);
614
615 col = uiLayoutColumn(layout, false);
616 uiItemR(col, ptr, "keep_sharp", UI_ITEM_NONE, nullptr, ICON_NONE);
617 uiItemR(col, ptr, "use_face_influence", UI_ITEM_NONE, nullptr, ICON_NONE);
618
619 modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr);
620
621 modifier_panel_end(layout, ptr);
622}
623
624static void panel_register(ARegionType *region_type)
625{
627}
628
630 /*idname*/ "WeightedNormal",
631 /*name*/ N_("WeightedNormal"),
632 /*struct_name*/ "WeightedNormalModifierData",
633 /*struct_size*/ sizeof(WeightedNormalModifierData),
634 /*srna*/ &RNA_WeightedNormalModifier,
638 /*icon*/ ICON_MOD_NORMALEDIT,
639
640 /*copy_data*/ BKE_modifier_copydata_generic,
641
642 /*deform_verts*/ nullptr,
643 /*deform_matrices*/ nullptr,
644 /*deform_verts_EM*/ nullptr,
645 /*deform_matrices_EM*/ nullptr,
646 /*modify_mesh*/ modify_mesh,
647 /*modify_geometry_set*/ nullptr,
648
649 /*init_data*/ init_data,
650 /*required_data_mask*/ required_data_mask,
651 /*free_data*/ nullptr,
652 /*is_disabled*/ nullptr,
653 /*update_depsgraph*/ nullptr,
654 /*depends_on_time*/ nullptr,
655 /*depends_on_normals*/ nullptr,
656 /*foreach_ID_link*/ nullptr,
657 /*foreach_tex_link*/ nullptr,
658 /*free_runtime_data*/ nullptr,
659 /*panel_register*/ panel_register,
660 /*blend_write*/ nullptr,
661 /*blend_read*/ nullptr,
662 /*foreach_cache*/ nullptr,
663};
@ CD_SET_DEFAULT
const void * CustomData_get_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void * CustomData_get_layer_for_write(CustomData *data, eCustomDataType type, int totelem)
void * CustomData_add_layer(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem)
support for deformation groups and hooks.
MDeformWeight * BKE_defvert_find_index(const MDeformVert *dv, int defgroup)
Definition deform.cc:795
@ LIB_ID_COPY_LOCALIZE
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:760
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_SupportsMapping
@ eModifierTypeFlag_EnableInEditmode
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsMesh
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define M_PI
MINLINE int compare_ff(float a, float b, float max_diff)
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
MINLINE float normalize_v3(float n[3])
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define IFACE_(msgid)
#define CD_MASK_MDEFORMVERT
@ CD_CUSTOMLOOPNORMAL
@ CD_PROP_INT32
#define CD_MASK_PROP_INT32
#define CD_MASK_CUSTOMLOOPNORMAL
#define DNA_struct_default_get(struct_name)
struct WeightedNormalModifierData WeightedNormalModifierData
@ eModifierType_WeightedNormal
#define MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID
@ MOD_WEIGHTEDNORMAL_MODE_FACE
@ MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE
@ MOD_WEIGHTEDNORMAL_MODE_ANGLE
@ MOD_WEIGHTEDNORMAL_KEEP_SHARP
@ MOD_WEIGHTEDNORMAL_FACE_INFLUENCE
@ MOD_WEIGHTEDNORMAL_INVERT_VGROUP
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
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_vgroup_ui(uiLayout *layout, PointerRNA *ptr, PointerRNA *ob_ptr, const char *vgroup_prop, const char *invert_vgroup_prop, const char *text)
void MOD_get_vgroup(const Object *ob, const Mesh *mesh, const char *name, const MDeformVert **dvert, int *defgrp_index)
Definition MOD_util.cc:159
static void init_data(ModifierData *md)
static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
static void aggregate_item_normal(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data, WeightedNormalDataAggregateItem *item_data, const int mv_index, const int face_index, const float curr_val, const bool use_face_influence)
static void panel_register(ARegionType *region_type)
static void wn_corner_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
static void wn_face_area(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
#define NUM_CACHED_INVERSE_POWERS_OF_WEIGHT
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
ModifierTypeInfo modifierType_WeightedNormal
static int modepair_cmp_by_val_inverse(const void *p1, const void *p2)
static bool check_item_face_strength(WeightedNormalData *wn_data, WeightedNormalDataAggregateItem *item_data, const int face_index)
static void panel_draw(const bContext *, Panel *panel)
static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
#define CLNORS_VALID_VEC_LEN
static void wn_face_with_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ FACE_STRENGTH_WEAK
IndexRange index_range() const
Definition BLI_array.hh:349
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
constexpr T * data() const
Definition BLI_span.hh:540
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr int64_t size() const
Definition BLI_span.hh:253
#define powf(x, y)
draw_view in_light_buf[] float
uint col
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
static char faces[256]
void normals_corner_custom_set_from_verts(Span< float3 > vert_positions, Span< int2 > edges, OffsetIndices< int > faces, Span< int > corner_verts, Span< int > corner_edges, Span< float3 > vert_normals, Span< float3 > face_normals, Span< bool > sharp_faces, MutableSpan< bool > sharp_edges, MutableSpan< float3 > r_custom_vert_normals, MutableSpan< short2 > r_clnors_data)
void face_angles_calc(Span< float3 > vert_positions, Span< int > face_verts, MutableSpan< float > angles)
float face_area_calc(Span< float3 > vert_positions, Span< int > face_verts)
void normals_calc_corners(Span< float3 > vert_positions, Span< int2 > edges, OffsetIndices< int > faces, Span< int > corner_verts, Span< int > corner_edges, Span< int > corner_to_face_map, Span< float3 > vert_normals, Span< float3 > face_normals, Span< bool > sharp_edges, Span< bool > sharp_faces, const short2 *clnors_data, CornerNormalSpaceArray *r_lnors_spacearr, MutableSpan< float3 > r_corner_normals)
void normals_corner_custom_set(Span< float3 > vert_positions, Span< int2 > edges, OffsetIndices< int > faces, Span< int > corner_verts, Span< int > corner_edges, 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)
struct uiLayout * layout
blender::MutableSpan< blender::short2 > clnors
blender::Span< int > corner_edges
blender::Span< int > loop_to_face
blender::Span< blender::int2 > edges
blender::VArraySpan< bool > sharp_faces
blender::Span< WeightedNormalDataAggregateItem > items_data
blender::Span< int > corner_verts
blender::Span< blender::float3 > vert_positions
blender::Span< blender::float3 > face_normals
const MDeformVert * dvert
blender::MutableSpan< bool > sharp_edges
blender::OffsetIndices< int > faces
blender::Span< blender::float3 > vert_normals
float cached_inverse_powers_of_weight[NUM_CACHED_INVERSE_POWERS_OF_WEIGHT]
Array< CornerNormalSpace > spaces
Definition BKE_mesh.hh:141
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126