Changeset View
Changeset View
Standalone View
Standalone View
source/blender/modifiers/intern/MOD_weighted_normal.cc
| Show All 17 Lines | |||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "DNA_screen_types.h" | #include "DNA_screen_types.h" | ||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_deform.h" | #include "BKE_deform.h" | ||||
| #include "BKE_lib_id.h" | #include "BKE_lib_id.h" | ||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | ||||
| #include "BKE_mesh_mapping.h" | |||||
| #include "BKE_screen.h" | #include "BKE_screen.h" | ||||
| #include "UI_interface.h" | #include "UI_interface.h" | ||||
| #include "UI_resources.h" | #include "UI_resources.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "RNA_prototypes.h" | #include "RNA_prototypes.h" | ||||
| Show All 37 Lines | struct WeightedNormalData { | ||||
| int loops_num; | int loops_num; | ||||
| int polys_num; | int polys_num; | ||||
| const MVert *mvert; | const MVert *mvert; | ||||
| const float (*vert_normals)[3]; | const float (*vert_normals)[3]; | ||||
| MEdge *medge; | MEdge *medge; | ||||
| const MLoop *mloop; | const MLoop *mloop; | ||||
| blender::Span<int> loop_to_poly; | |||||
| short (*clnors)[2]; | short (*clnors)[2]; | ||||
| bool has_clnors; /* True if clnors already existed, false if we had to create them. */ | bool has_clnors; /* True if clnors already existed, false if we had to create them. */ | ||||
| float split_angle; | float split_angle; | ||||
| const MPoly *mpoly; | const MPoly *mpoly; | ||||
| const float (*polynors)[3]; | const float (*polynors)[3]; | ||||
| const int *poly_strength; | const int *poly_strength; | ||||
| const MDeformVert *dvert; | const MDeformVert *dvert; | ||||
| int defgrp_index; | int defgrp_index; | ||||
| bool use_invert_vgroup; | bool use_invert_vgroup; | ||||
| float weight; | float weight; | ||||
| short mode; | short mode; | ||||
| /* Lower-level, internal processing data. */ | /* Lower-level, internal processing data. */ | ||||
| float cached_inverse_powers_of_weight[NUM_CACHED_INVERSE_POWERS_OF_WEIGHT]; | float cached_inverse_powers_of_weight[NUM_CACHED_INVERSE_POWERS_OF_WEIGHT]; | ||||
| WeightedNormalDataAggregateItem *items_data; | WeightedNormalDataAggregateItem *items_data; | ||||
| ModePair *mode_pair; | ModePair *mode_pair; | ||||
| int *loop_to_poly; | |||||
| }; | }; | ||||
| /** | /** | ||||
| * Check strength of given poly compared to those found so far for that given item | * Check strength of given poly compared to those found so far for that given item | ||||
| * (vertex or smooth fan), and reset matching item_data in case we get a stronger new strength. | * (vertex or smooth fan), and reset matching item_data in case we get a stronger new strength. | ||||
| */ | */ | ||||
| static bool check_item_poly_strength(WeightedNormalData *wn_data, | static bool check_item_poly_strength(WeightedNormalData *wn_data, | ||||
| WeightedNormalDataAggregateItem *item_data, | WeightedNormalDataAggregateItem *item_data, | ||||
| ▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | const float inverted_n_weight = loops_num < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT ? | ||||
| 1.0f / powf(weight, loops_num); | 1.0f / powf(weight, loops_num); | ||||
| madd_v3_v3fl(item_data->normal, polynors[mp_index], curr_val * inverted_n_weight); | madd_v3_v3fl(item_data->normal, polynors[mp_index], curr_val * inverted_n_weight); | ||||
| } | } | ||||
| static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, | static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, | ||||
| WeightedNormalData *wn_data) | WeightedNormalData *wn_data) | ||||
| { | { | ||||
| using namespace blender; | |||||
| const int verts_num = wn_data->verts_num; | const int verts_num = wn_data->verts_num; | ||||
| const int edges_num = wn_data->edges_num; | const int edges_num = wn_data->edges_num; | ||||
| const int loops_num = wn_data->loops_num; | const int loops_num = wn_data->loops_num; | ||||
| const int polys_num = wn_data->polys_num; | const int polys_num = wn_data->polys_num; | ||||
| const MVert *mvert = wn_data->mvert; | const MVert *mvert = wn_data->mvert; | ||||
| MEdge *medge = wn_data->medge; | MEdge *medge = wn_data->medge; | ||||
| const MLoop *mloop = wn_data->mloop; | const MLoop *mloop = wn_data->mloop; | ||||
| short(*clnors)[2] = wn_data->clnors; | short(*clnors)[2] = wn_data->clnors; | ||||
| int *loop_to_poly = wn_data->loop_to_poly; | const Span<int> loop_to_poly = wn_data->loop_to_poly; | ||||
| const MPoly *mpoly = wn_data->mpoly; | const MPoly *mpoly = wn_data->mpoly; | ||||
| const float(*polynors)[3] = wn_data->polynors; | const float(*polynors)[3] = wn_data->polynors; | ||||
| const int *poly_strength = wn_data->poly_strength; | const int *poly_strength = wn_data->poly_strength; | ||||
| const MDeformVert *dvert = wn_data->dvert; | const MDeformVert *dvert = wn_data->dvert; | ||||
| const short mode = wn_data->mode; | const short mode = wn_data->mode; | ||||
| Show All 27 Lines | BKE_mesh_normals_loop_split(mvert, | ||||
| mloop, | mloop, | ||||
| loop_normals, | loop_normals, | ||||
| loops_num, | loops_num, | ||||
| mpoly, | mpoly, | ||||
| polynors, | polynors, | ||||
| polys_num, | polys_num, | ||||
| true, | true, | ||||
| split_angle, | split_angle, | ||||
| loop_to_poly.data(), | |||||
| &lnors_spacearr, | &lnors_spacearr, | ||||
| has_clnors ? clnors : nullptr, | has_clnors ? clnors : nullptr); | ||||
| loop_to_poly); | |||||
| items_num = lnors_spacearr.spaces_num; | items_num = lnors_spacearr.spaces_num; | ||||
| items_data = static_cast<WeightedNormalDataAggregateItem *>( | items_data = static_cast<WeightedNormalDataAggregateItem *>( | ||||
| MEM_calloc_arrayN(size_t(items_num), sizeof(*items_data), __func__)); | MEM_calloc_arrayN(size_t(items_num), sizeof(*items_data), __func__)); | ||||
| /* In this first loop, we assign each WeightedNormalDataAggregateItem | /* In this first loop, we assign each WeightedNormalDataAggregateItem | ||||
| * to its smooth fan of loops (aka lnor space). */ | * to its smooth fan of loops (aka lnor space). */ | ||||
| const MPoly *mp; | const MPoly *mp; | ||||
| ▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | case MOD_WEIGHTEDNORMAL_MODE_FACE: | ||||
| aggregate_item_normal( | aggregate_item_normal( | ||||
| wnmd, wn_data, item_data, mv_index, mp_index, mp_val, use_face_influence); | wnmd, wn_data, item_data, mv_index, mp_index, mp_val, use_face_influence); | ||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| case MOD_WEIGHTEDNORMAL_MODE_ANGLE: | case MOD_WEIGHTEDNORMAL_MODE_ANGLE: | ||||
| case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE: | case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE: | ||||
| BLI_assert(loop_to_poly != nullptr); | |||||
| for (int i = 0; i < loops_num; i++) { | for (int i = 0; i < loops_num; i++) { | ||||
| const int ml_index = mode_pair[i].index; | const int ml_index = mode_pair[i].index; | ||||
| const float ml_val = mode_pair[i].val; | const float ml_val = mode_pair[i].val; | ||||
| const int mp_index = loop_to_poly[ml_index]; | const int mp_index = loop_to_poly[ml_index]; | ||||
| const int mv_index = mloop[ml_index].v; | const int mv_index = mloop[ml_index].v; | ||||
| WeightedNormalDataAggregateItem *item_data = | WeightedNormalDataAggregateItem *item_data = | ||||
| keep_sharp ? static_cast<WeightedNormalDataAggregateItem *>( | keep_sharp ? static_cast<WeightedNormalDataAggregateItem *>( | ||||
| ▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | else { | ||||
| mloop, | mloop, | ||||
| loop_normals, | loop_normals, | ||||
| loops_num, | loops_num, | ||||
| mpoly, | mpoly, | ||||
| polynors, | polynors, | ||||
| polys_num, | polys_num, | ||||
| true, | true, | ||||
| split_angle, | split_angle, | ||||
| loop_to_poly.data(), | |||||
| nullptr, | nullptr, | ||||
| has_clnors ? clnors : nullptr, | has_clnors ? clnors : nullptr); | ||||
| loop_to_poly); | |||||
| for (int ml_index = 0; ml_index < loops_num; ml_index++) { | for (int ml_index = 0; ml_index < loops_num; ml_index++) { | ||||
| const int item_index = mloop[ml_index].v; | const int item_index = mloop[ml_index].v; | ||||
| if (!is_zero_v3(items_data[item_index].normal)) { | if (!is_zero_v3(items_data[item_index].normal)) { | ||||
| copy_v3_v3(loop_normals[ml_index], items_data[item_index].normal); | copy_v3_v3(loop_normals[ml_index], items_data[item_index].normal); | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | static void wn_corner_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data) | ||||
| const MVert *mvert = wn_data->mvert; | const MVert *mvert = wn_data->mvert; | ||||
| const MLoop *mloop = wn_data->mloop; | const MLoop *mloop = wn_data->mloop; | ||||
| const MPoly *mpoly = wn_data->mpoly; | const MPoly *mpoly = wn_data->mpoly; | ||||
| const MPoly *mp; | const MPoly *mp; | ||||
| int mp_index; | int mp_index; | ||||
| int *loop_to_poly = static_cast<int *>( | |||||
| MEM_malloc_arrayN(size_t(loops_num), sizeof(*loop_to_poly), __func__)); | |||||
| ModePair *corner_angle = static_cast<ModePair *>( | ModePair *corner_angle = static_cast<ModePair *>( | ||||
| MEM_malloc_arrayN(size_t(loops_num), sizeof(*corner_angle), __func__)); | MEM_malloc_arrayN(size_t(loops_num), sizeof(*corner_angle), __func__)); | ||||
| for (mp_index = 0, mp = mpoly; mp_index < polys_num; mp_index++, mp++) { | for (mp_index = 0, mp = mpoly; mp_index < polys_num; mp_index++, mp++) { | ||||
| const MLoop *ml_start = &mloop[mp->loopstart]; | const MLoop *ml_start = &mloop[mp->loopstart]; | ||||
| float *index_angle = static_cast<float *>( | float *index_angle = static_cast<float *>( | ||||
| MEM_malloc_arrayN(size_t(mp->totloop), sizeof(*index_angle), __func__)); | MEM_malloc_arrayN(size_t(mp->totloop), sizeof(*index_angle), __func__)); | ||||
| BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle); | BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle); | ||||
| ModePair *c_angl = &corner_angle[mp->loopstart]; | ModePair *c_angl = &corner_angle[mp->loopstart]; | ||||
| float *angl = index_angle; | float *angl = index_angle; | ||||
| for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; | for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; | ||||
| ml_index++, c_angl++, angl++) { | ml_index++, c_angl++, angl++) { | ||||
| c_angl->val = float(M_PI) - *angl; | c_angl->val = float(M_PI) - *angl; | ||||
| c_angl->index = ml_index; | c_angl->index = ml_index; | ||||
| loop_to_poly[ml_index] = mp_index; | |||||
| } | } | ||||
| MEM_freeN(index_angle); | MEM_freeN(index_angle); | ||||
| } | } | ||||
| qsort(corner_angle, loops_num, sizeof(*corner_angle), modepair_cmp_by_val_inverse); | qsort(corner_angle, loops_num, sizeof(*corner_angle), modepair_cmp_by_val_inverse); | ||||
| wn_data->loop_to_poly = loop_to_poly; | |||||
| wn_data->mode_pair = corner_angle; | wn_data->mode_pair = corner_angle; | ||||
| apply_weights_vertex_normal(wnmd, wn_data); | apply_weights_vertex_normal(wnmd, wn_data); | ||||
| } | } | ||||
| static void wn_face_with_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data) | static void wn_face_with_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data) | ||||
| { | { | ||||
| const int loops_num = wn_data->loops_num; | const int loops_num = wn_data->loops_num; | ||||
| const int polys_num = wn_data->polys_num; | const int polys_num = wn_data->polys_num; | ||||
| const MVert *mvert = wn_data->mvert; | const MVert *mvert = wn_data->mvert; | ||||
| const MLoop *mloop = wn_data->mloop; | const MLoop *mloop = wn_data->mloop; | ||||
| const MPoly *mpoly = wn_data->mpoly; | const MPoly *mpoly = wn_data->mpoly; | ||||
| const MPoly *mp; | const MPoly *mp; | ||||
| int mp_index; | int mp_index; | ||||
| int *loop_to_poly = static_cast<int *>( | |||||
| MEM_malloc_arrayN(size_t(loops_num), sizeof(*loop_to_poly), __func__)); | |||||
| ModePair *combined = static_cast<ModePair *>( | ModePair *combined = static_cast<ModePair *>( | ||||
| MEM_malloc_arrayN(size_t(loops_num), sizeof(*combined), __func__)); | MEM_malloc_arrayN(size_t(loops_num), sizeof(*combined), __func__)); | ||||
| for (mp_index = 0, mp = mpoly; mp_index < polys_num; mp_index++, mp++) { | for (mp_index = 0, mp = mpoly; mp_index < polys_num; mp_index++, mp++) { | ||||
| const MLoop *ml_start = &mloop[mp->loopstart]; | const MLoop *ml_start = &mloop[mp->loopstart]; | ||||
| float face_area = BKE_mesh_calc_poly_area(mp, ml_start, mvert); | float face_area = BKE_mesh_calc_poly_area(mp, ml_start, mvert); | ||||
| float *index_angle = static_cast<float *>( | float *index_angle = static_cast<float *>( | ||||
| MEM_malloc_arrayN(size_t(mp->totloop), sizeof(*index_angle), __func__)); | MEM_malloc_arrayN(size_t(mp->totloop), sizeof(*index_angle), __func__)); | ||||
| BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle); | BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle); | ||||
| ModePair *cmbnd = &combined[mp->loopstart]; | ModePair *cmbnd = &combined[mp->loopstart]; | ||||
| float *angl = index_angle; | float *angl = index_angle; | ||||
| for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; | for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; | ||||
| ml_index++, cmbnd++, angl++) { | ml_index++, cmbnd++, angl++) { | ||||
| /* In this case val is product of corner angle and face area. */ | /* In this case val is product of corner angle and face area. */ | ||||
| cmbnd->val = (float(M_PI) - *angl) * face_area; | cmbnd->val = (float(M_PI) - *angl) * face_area; | ||||
| cmbnd->index = ml_index; | cmbnd->index = ml_index; | ||||
| loop_to_poly[ml_index] = mp_index; | |||||
| } | } | ||||
| MEM_freeN(index_angle); | MEM_freeN(index_angle); | ||||
| } | } | ||||
| qsort(combined, loops_num, sizeof(*combined), modepair_cmp_by_val_inverse); | qsort(combined, loops_num, sizeof(*combined), modepair_cmp_by_val_inverse); | ||||
| wn_data->loop_to_poly = loop_to_poly; | |||||
| wn_data->mode_pair = combined; | wn_data->mode_pair = combined; | ||||
| apply_weights_vertex_normal(wnmd, wn_data); | apply_weights_vertex_normal(wnmd, wn_data); | ||||
| } | } | ||||
| static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) | static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) | ||||
| { | { | ||||
| using namespace blender; | |||||
| WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md; | WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md; | ||||
| Object *ob = ctx->object; | Object *ob = ctx->object; | ||||
| /* XXX TODO(Rohan Rathi): | /* XXX TODO(Rohan Rathi): | ||||
| * Once we fully switch to Mesh evaluation of modifiers, | * Once we fully switch to Mesh evaluation of modifiers, | ||||
| * we can expect to get that flag from the COW copy. | * we can expect to get that flag from the COW copy. | ||||
| * But for now, it is lost in the DM intermediate step, | * But for now, it is lost in the DM intermediate step, | ||||
| * so we need to directly check orig object's data. */ | * so we need to directly check orig object's data. */ | ||||
| ▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | if (!clnors) { | ||||
| clnors = static_cast<short(*)[2]>(CustomData_add_layer( | clnors = static_cast<short(*)[2]>(CustomData_add_layer( | ||||
| &result->ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, nullptr, loops_num)); | &result->ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, nullptr, loops_num)); | ||||
| } | } | ||||
| const MDeformVert *dvert; | const MDeformVert *dvert; | ||||
| int defgrp_index; | int defgrp_index; | ||||
| MOD_get_vgroup(ctx->object, mesh, wnmd->defgrp_name, &dvert, &defgrp_index); | MOD_get_vgroup(ctx->object, mesh, wnmd->defgrp_name, &dvert, &defgrp_index); | ||||
| const Array<int> loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(result->polys(), | |||||
| result->totloop); | |||||
| WeightedNormalData wn_data{}; | WeightedNormalData wn_data{}; | ||||
| wn_data.verts_num = verts_num; | wn_data.verts_num = verts_num; | ||||
| wn_data.edges_num = edges_num; | wn_data.edges_num = edges_num; | ||||
| wn_data.loops_num = loops_num; | wn_data.loops_num = loops_num; | ||||
| wn_data.polys_num = polys_num; | wn_data.polys_num = polys_num; | ||||
| wn_data.mvert = mvert; | wn_data.mvert = mvert; | ||||
| wn_data.vert_normals = BKE_mesh_vertex_normals_ensure(result); | wn_data.vert_normals = BKE_mesh_vertex_normals_ensure(result); | ||||
| wn_data.medge = medge; | wn_data.medge = medge; | ||||
| wn_data.mloop = mloop; | wn_data.mloop = mloop; | ||||
| wn_data.loop_to_poly = loop_to_poly_map; | |||||
| wn_data.clnors = clnors; | wn_data.clnors = clnors; | ||||
| wn_data.has_clnors = has_clnors; | wn_data.has_clnors = has_clnors; | ||||
| wn_data.split_angle = split_angle; | wn_data.split_angle = split_angle; | ||||
| wn_data.mpoly = mpoly; | wn_data.mpoly = mpoly; | ||||
| wn_data.polynors = BKE_mesh_poly_normals_ensure(mesh); | wn_data.polynors = BKE_mesh_poly_normals_ensure(mesh); | ||||
| wn_data.poly_strength = static_cast<const int *>(CustomData_get_layer_named( | wn_data.poly_strength = static_cast<const int *>(CustomData_get_layer_named( | ||||
| &result->pdata, CD_PROP_INT32, MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID)); | &result->pdata, CD_PROP_INT32, MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID)); | ||||
| Show All 12 Lines | switch (wnmd->mode) { | ||||
| case MOD_WEIGHTEDNORMAL_MODE_ANGLE: | case MOD_WEIGHTEDNORMAL_MODE_ANGLE: | ||||
| wn_corner_angle(wnmd, &wn_data); | wn_corner_angle(wnmd, &wn_data); | ||||
| break; | break; | ||||
| case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE: | case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE: | ||||
| wn_face_with_angle(wnmd, &wn_data); | wn_face_with_angle(wnmd, &wn_data); | ||||
| break; | break; | ||||
| } | } | ||||
| MEM_SAFE_FREE(wn_data.loop_to_poly); | |||||
| MEM_SAFE_FREE(wn_data.mode_pair); | MEM_SAFE_FREE(wn_data.mode_pair); | ||||
| MEM_SAFE_FREE(wn_data.items_data); | MEM_SAFE_FREE(wn_data.items_data); | ||||
| result->runtime->is_original_bmesh = false; | result->runtime->is_original_bmesh = false; | ||||
| return result; | return result; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 91 Lines • Show Last 20 Lines | |||||