Changeset View
Changeset View
Standalone View
Standalone View
source/blender/modifiers/intern/MOD_correctivesmooth.c
| Show First 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
| #include "DEG_depsgraph_query.h" | #include "DEG_depsgraph_query.h" | ||||
| // #define DEBUG_TIME | // #define DEBUG_TIME | ||||
| #include "PIL_time.h" | #include "PIL_time.h" | ||||
| #ifdef DEBUG_TIME | #ifdef DEBUG_TIME | ||||
| # include "PIL_time_utildefines.h" | # include "PIL_time_utildefines.h" | ||||
| #endif | |||||
| /* minor optimization, calculate this inline */ | #endif | ||||
| #define USE_TANGENT_CALC_INLINE | |||||
| static void initData(ModifierData *md) | static void initData(ModifierData *md) | ||||
| { | { | ||||
| CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; | CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; | ||||
| BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(csmd, modifier)); | BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(csmd, modifier)); | ||||
| MEMCPY_STRUCT_AFTER(csmd, DNA_struct_default_get(CorrectiveSmoothModifierData), modifier); | MEMCPY_STRUCT_AFTER(csmd, DNA_struct_default_get(CorrectiveSmoothModifierData), modifier); | ||||
| Show All 10 Lines | static void copyData(const ModifierData *md, ModifierData *target, const int flag) | ||||
| BKE_modifier_copydata_generic(md, target, flag); | BKE_modifier_copydata_generic(md, target, flag); | ||||
| if (csmd->bind_coords) { | if (csmd->bind_coords) { | ||||
| tcsmd->bind_coords = MEM_dupallocN(csmd->bind_coords); | tcsmd->bind_coords = MEM_dupallocN(csmd->bind_coords); | ||||
| } | } | ||||
| tcsmd->delta_cache.deltas = NULL; | tcsmd->delta_cache.deltas = NULL; | ||||
| tcsmd->delta_cache.totverts = 0; | tcsmd->delta_cache.deltas_num = 0; | ||||
| } | } | ||||
| static void freeBind(CorrectiveSmoothModifierData *csmd) | static void freeBind(CorrectiveSmoothModifierData *csmd) | ||||
| { | { | ||||
| MEM_SAFE_FREE(csmd->bind_coords); | MEM_SAFE_FREE(csmd->bind_coords); | ||||
| MEM_SAFE_FREE(csmd->delta_cache.deltas); | MEM_SAFE_FREE(csmd->delta_cache.deltas); | ||||
| csmd->bind_coords_num = 0; | csmd->bind_coords_num = 0; | ||||
| ▲ Show 20 Lines • Show All 297 Lines • ▼ Show 20 Lines | static void smooth_verts(CorrectiveSmoothModifierData *csmd, | ||||
| smooth_iter(csmd, mesh, vertexCos, verts_num, smooth_weights, (uint)csmd->repeat); | smooth_iter(csmd, mesh, vertexCos, verts_num, smooth_weights, (uint)csmd->repeat); | ||||
| if (smooth_weights) { | if (smooth_weights) { | ||||
| MEM_freeN(smooth_weights); | MEM_freeN(smooth_weights); | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * finalize after accumulation. | * Calculate an orthogonal 3x3 matrix from 2 edge vectors. | ||||
| */ | * \return false if this loop should be ignored (have zero influence). | ||||
| static void calc_tangent_ortho(float ts[3][3]) | |||||
| { | |||||
| float v_tan_a[3], v_tan_b[3]; | |||||
| float t_vec_a[3], t_vec_b[3]; | |||||
| normalize_v3(ts[2]); | |||||
| copy_v3_v3(v_tan_a, ts[0]); | |||||
| copy_v3_v3(v_tan_b, ts[1]); | |||||
| cross_v3_v3v3(ts[1], ts[2], v_tan_a); | |||||
| mul_v3_fl(ts[1], dot_v3v3(ts[1], v_tan_b) < 0.0f ? -1.0f : 1.0f); | |||||
| /* Orthogonalize tangent. */ | |||||
| mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], v_tan_a)); | |||||
| sub_v3_v3v3(ts[0], v_tan_a, t_vec_a); | |||||
| /* Orthogonalize bi-tangent. */ | |||||
| mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], ts[1])); | |||||
| mul_v3_v3fl(t_vec_b, ts[0], dot_v3v3(ts[0], ts[1]) / dot_v3v3(v_tan_a, v_tan_a)); | |||||
| sub_v3_v3(ts[1], t_vec_a); | |||||
| sub_v3_v3(ts[1], t_vec_b); | |||||
| normalize_v3(ts[0]); | |||||
| normalize_v3(ts[1]); | |||||
| } | |||||
| /** | |||||
| * accumulate edge-vectors from all polys. | |||||
| */ | */ | ||||
| static void calc_tangent_loop_accum(const float v_dir_prev[3], | static bool calc_tangent_loop(const float v_dir_prev[3], | ||||
| const float v_dir_next[3], | const float v_dir_next[3], | ||||
| float r_tspace[3][3]) | float r_tspace[3][3]) | ||||
| { | { | ||||
| add_v3_v3v3(r_tspace[1], v_dir_prev, v_dir_next); | if (UNLIKELY(compare_v3v3(v_dir_prev, v_dir_next, FLT_EPSILON * 10.0f))) { | ||||
| /* As there are no weights, the value doesn't matter just initialize it. */ | |||||
| unit_m3(r_tspace); | |||||
| return false; | |||||
| } | |||||
| if (compare_v3v3(v_dir_prev, v_dir_next, FLT_EPSILON * 10.0f) == false) { | copy_v3_v3(r_tspace[0], v_dir_prev); | ||||
| const float weight = fabsf(acosf(dot_v3v3(v_dir_next, v_dir_prev))); | copy_v3_v3(r_tspace[1], v_dir_next); | ||||
| float nor[3]; | |||||
| cross_v3_v3v3(nor, v_dir_prev, v_dir_next); | cross_v3_v3v3(r_tspace[2], v_dir_prev, v_dir_next); | ||||
| normalize_v3(nor); | normalize_v3(r_tspace[2]); | ||||
| cross_v3_v3v3(r_tspace[0], r_tspace[1], nor); | /* Make orthogonal using `r_tspace[2]` as a basis. | ||||
| * | |||||
| * NOTE: while it seems more logical to use `v_dir_prev` & `v_dir_next` as separate X/Y axis | |||||
| * (instead of combining them as is done here). It's not necessary as the directions of the | |||||
| * axis aren't important as long as the difference between tangent matrices is equivalent. | |||||
| * Some computations can be skipped by combining the the two directions, | |||||
| * using the cross product for the 3rd axes. */ | |||||
| add_v3_v3(r_tspace[0], r_tspace[1]); | |||||
| normalize_v3(r_tspace[0]); | |||||
| cross_v3_v3v3(r_tspace[1], r_tspace[2], r_tspace[0]); | |||||
| mul_v3_fl(nor, weight); | return true; | ||||
| /* accumulate weighted normals */ | |||||
| add_v3_v3(r_tspace[2], nor); | |||||
| } | |||||
| } | } | ||||
| static void calc_tangent_spaces(Mesh *mesh, float (*vertexCos)[3], float (*r_tangent_spaces)[3][3]) | /** | ||||
| * \param r_tangent_spaces: Loop aligned array of tangents. | |||||
| * \param r_tangent_weights: Loop aligned array of weights (may be NULL). | |||||
| * \param r_tangent_weights_per_vertex: Vertex aligned array, accumulating weights for each loop | |||||
| * (may be NULL). | |||||
| */ | |||||
| static void calc_tangent_spaces(const Mesh *mesh, | |||||
| const float (*vertexCos)[3], | |||||
| float (*r_tangent_spaces)[3][3], | |||||
| float *r_tangent_weights, | |||||
| float *r_tangent_weights_per_vertex) | |||||
| { | { | ||||
| const uint mpoly_num = (uint)mesh->totpoly; | const uint mpoly_num = (uint)mesh->totpoly; | ||||
| #ifndef USE_TANGENT_CALC_INLINE | const uint mvert_num = (uint)mesh->totvert; | ||||
| const uint mvert_num = (uint)dm->getNumVerts(dm); | |||||
| #endif | |||||
| const MPoly *mpoly = mesh->mpoly; | const MPoly *mpoly = mesh->mpoly; | ||||
| const MLoop *mloop = mesh->mloop; | const MLoop *mloop = mesh->mloop; | ||||
| uint i; | uint i; | ||||
| if (r_tangent_weights_per_vertex != NULL) { | |||||
| copy_vn_fl(r_tangent_weights_per_vertex, (int)mvert_num, 0.0f); | |||||
| } | |||||
| for (i = 0; i < mpoly_num; i++) { | for (i = 0; i < mpoly_num; i++) { | ||||
| const MPoly *mp = &mpoly[i]; | const MPoly *mp = &mpoly[i]; | ||||
| const MLoop *l_next = &mloop[mp->loopstart]; | const MLoop *l_next = &mloop[mp->loopstart]; | ||||
| const MLoop *l_term = l_next + mp->totloop; | const MLoop *l_term = l_next + mp->totloop; | ||||
| const MLoop *l_prev = l_term - 2; | const MLoop *l_prev = l_term - 2; | ||||
| const MLoop *l_curr = l_term - 1; | const MLoop *l_curr = l_term - 1; | ||||
| /* loop directions */ | /* loop directions */ | ||||
| float v_dir_prev[3], v_dir_next[3]; | float v_dir_prev[3], v_dir_next[3]; | ||||
| /* needed entering the loop */ | /* needed entering the loop */ | ||||
| sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]); | sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]); | ||||
| normalize_v3(v_dir_prev); | normalize_v3(v_dir_prev); | ||||
| for (; l_next != l_term; l_prev = l_curr, l_curr = l_next, l_next++) { | for (; l_next != l_term; l_prev = l_curr, l_curr = l_next, l_next++) { | ||||
| float(*ts)[3] = r_tangent_spaces[l_curr->v]; | uint l_index = (uint)(l_curr - mloop); | ||||
| float(*ts)[3] = r_tangent_spaces[l_index]; | |||||
| /* re-use the previous value */ | /* re-use the previous value */ | ||||
| #if 0 | #if 0 | ||||
| sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]); | sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]); | ||||
| normalize_v3(v_dir_prev); | normalize_v3(v_dir_prev); | ||||
| #endif | #endif | ||||
| sub_v3_v3v3(v_dir_next, vertexCos[l_curr->v], vertexCos[l_next->v]); | sub_v3_v3v3(v_dir_next, vertexCos[l_curr->v], vertexCos[l_next->v]); | ||||
| normalize_v3(v_dir_next); | normalize_v3(v_dir_next); | ||||
| calc_tangent_loop_accum(v_dir_prev, v_dir_next, ts); | if (calc_tangent_loop(v_dir_prev, v_dir_next, ts)) { | ||||
| if (r_tangent_weights != NULL) { | |||||
| copy_v3_v3(v_dir_prev, v_dir_next); | const float weight = fabsf(acosf(dot_v3v3(v_dir_next, v_dir_prev))); | ||||
| r_tangent_weights[l_index] = weight; | |||||
| r_tangent_weights_per_vertex[l_curr->v] += weight; | |||||
| } | |||||
| } | |||||
| else { | |||||
| if (r_tangent_weights != NULL) { | |||||
| r_tangent_weights[l_index] = 0; | |||||
| } | } | ||||
| } | } | ||||
| /* do inline */ | copy_v3_v3(v_dir_prev, v_dir_next); | ||||
| #ifndef USE_TANGENT_CALC_INLINE | } | ||||
| for (i = 0; i < mvert_num; i++) { | |||||
| float(*ts)[3] = r_tangent_spaces[i]; | |||||
| calc_tangent_ortho(ts); | |||||
| } | } | ||||
| #endif | |||||
| } | } | ||||
| static void store_cache_settings(CorrectiveSmoothModifierData *csmd) | static void store_cache_settings(CorrectiveSmoothModifierData *csmd) | ||||
| { | { | ||||
| csmd->delta_cache.lambda = csmd->lambda; | csmd->delta_cache.lambda = csmd->lambda; | ||||
| csmd->delta_cache.repeat = csmd->repeat; | csmd->delta_cache.repeat = csmd->repeat; | ||||
| csmd->delta_cache.flag = csmd->flag; | csmd->delta_cache.flag = csmd->flag; | ||||
| csmd->delta_cache.smooth_type = csmd->smooth_type; | csmd->delta_cache.smooth_type = csmd->smooth_type; | ||||
| Show All 14 Lines | |||||
| */ | */ | ||||
| static void calc_deltas(CorrectiveSmoothModifierData *csmd, | static void calc_deltas(CorrectiveSmoothModifierData *csmd, | ||||
| Mesh *mesh, | Mesh *mesh, | ||||
| MDeformVert *dvert, | MDeformVert *dvert, | ||||
| const int defgrp_index, | const int defgrp_index, | ||||
| const float (*rest_coords)[3], | const float (*rest_coords)[3], | ||||
| uint verts_num) | uint verts_num) | ||||
| { | { | ||||
| const uint loops_num = (uint)mesh->totloop; | |||||
| float(*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords); | float(*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords); | ||||
| float(*tangent_spaces)[3][3]; | float(*tangent_spaces)[3][3]; | ||||
| uint i; | |||||
| tangent_spaces = MEM_calloc_arrayN(verts_num, sizeof(float[3][3]), __func__); | uint l_index; | ||||
| tangent_spaces = MEM_malloc_arrayN(loops_num, sizeof(float[3][3]), __func__); | |||||
| if (csmd->delta_cache.totverts != verts_num) { | if (csmd->delta_cache.deltas_num != loops_num) { | ||||
| MEM_SAFE_FREE(csmd->delta_cache.deltas); | MEM_SAFE_FREE(csmd->delta_cache.deltas); | ||||
| } | } | ||||
| /* allocate deltas if they have not yet been allocated, otherwise we will just write over them */ | /* allocate deltas if they have not yet been allocated, otherwise we will just write over them */ | ||||
| if (!csmd->delta_cache.deltas) { | if (!csmd->delta_cache.deltas) { | ||||
| csmd->delta_cache.totverts = verts_num; | csmd->delta_cache.deltas_num = loops_num; | ||||
| csmd->delta_cache.deltas = MEM_malloc_arrayN(verts_num, sizeof(float[3]), __func__); | csmd->delta_cache.deltas = MEM_malloc_arrayN(loops_num, sizeof(float[3]), __func__); | ||||
| } | } | ||||
| smooth_verts(csmd, mesh, dvert, defgrp_index, smooth_vertex_coords, verts_num); | smooth_verts(csmd, mesh, dvert, defgrp_index, smooth_vertex_coords, verts_num); | ||||
| calc_tangent_spaces(mesh, smooth_vertex_coords, tangent_spaces); | calc_tangent_spaces(mesh, smooth_vertex_coords, tangent_spaces, NULL, NULL); | ||||
| for (i = 0; i < verts_num; i++) { | copy_vn_fl(&csmd->delta_cache.deltas[0][0], (int)loops_num * 3, 0.0f); | ||||
| float imat[3][3], delta[3]; | |||||
| #ifdef USE_TANGENT_CALC_INLINE | for (l_index = 0; l_index < loops_num; l_index++) { | ||||
| calc_tangent_ortho(tangent_spaces[i]); | const int v_index = (int)mesh->mloop[l_index].v; | ||||
| #endif | float delta[3]; | ||||
| sub_v3_v3v3(delta, rest_coords[v_index], smooth_vertex_coords[v_index]); | |||||
| sub_v3_v3v3(delta, rest_coords[i], smooth_vertex_coords[i]); | float imat[3][3]; | ||||
| if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[i]))) { | if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[l_index]))) { | ||||
| transpose_m3_m3(imat, tangent_spaces[i]); | transpose_m3_m3(imat, tangent_spaces[l_index]); | ||||
| } | } | ||||
| mul_v3_m3v3(csmd->delta_cache.deltas[i], imat, delta); | mul_v3_m3v3(csmd->delta_cache.deltas[l_index], imat, delta); | ||||
| } | } | ||||
| MEM_freeN(tangent_spaces); | MEM_freeN(tangent_spaces); | ||||
| MEM_freeN(smooth_vertex_coords); | MEM_freeN(smooth_vertex_coords); | ||||
| } | } | ||||
| static void correctivesmooth_modifier_do(ModifierData *md, | static void correctivesmooth_modifier_do(ModifierData *md, | ||||
| Depsgraph *depsgraph, | Depsgraph *depsgraph, | ||||
| Object *ob, | Object *ob, | ||||
| Mesh *mesh, | Mesh *mesh, | ||||
| float (*vertexCos)[3], | float (*vertexCos)[3], | ||||
| uint verts_num, | uint verts_num, | ||||
| struct BMEditMesh *em) | struct BMEditMesh *em) | ||||
| { | { | ||||
| CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; | CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; | ||||
| const bool force_delta_cache_update = | const bool force_delta_cache_update = | ||||
| /* XXX, take care! if mesh data itself changes we need to forcefully recalculate deltas */ | /* XXX, take care! if mesh data itself changes we need to forcefully recalculate deltas */ | ||||
| !cache_settings_equal(csmd) || | !cache_settings_equal(csmd) || | ||||
| ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) && | ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) && | ||||
| (((ID *)ob->data)->recalc & ID_RECALC_ALL)); | (((ID *)ob->data)->recalc & ID_RECALC_ALL)); | ||||
| const uint loops_num = (uint)mesh->totloop; | |||||
| bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0; | bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0; | ||||
| MDeformVert *dvert = NULL; | MDeformVert *dvert = NULL; | ||||
| int defgrp_index; | int defgrp_index; | ||||
| MOD_get_vgroup(ob, mesh, csmd->defgrp_name, &dvert, &defgrp_index); | MOD_get_vgroup(ob, mesh, csmd->defgrp_name, &dvert, &defgrp_index); | ||||
| /* if rest bind_coords not are defined, set them (only run during bind) */ | /* if rest bind_coords not are defined, set them (only run during bind) */ | ||||
| if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && | if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && | ||||
| ▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | else { | ||||
| BKE_modifier_set_error( | BKE_modifier_set_error( | ||||
| ob, md, "Original vertex count mismatch: %u to %u", me_numVerts, verts_num); | ob, md, "Original vertex count mismatch: %u to %u", me_numVerts, verts_num); | ||||
| goto error; | goto error; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* check to see if our deltas are still valid */ | /* check to see if our deltas are still valid */ | ||||
| if (!csmd->delta_cache.deltas || (csmd->delta_cache.totverts != verts_num) || | if (!csmd->delta_cache.deltas || (csmd->delta_cache.deltas_num != loops_num) || | ||||
| force_delta_cache_update) { | force_delta_cache_update) { | ||||
| const float(*rest_coords)[3]; | const float(*rest_coords)[3]; | ||||
| bool is_rest_coords_alloc = false; | bool is_rest_coords_alloc = false; | ||||
| store_cache_settings(csmd); | store_cache_settings(csmd); | ||||
| if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { | if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { | ||||
| /* caller needs to do sanity check here */ | /* caller needs to do sanity check here */ | ||||
| Show All 31 Lines | |||||
| #ifdef DEBUG_TIME | #ifdef DEBUG_TIME | ||||
| TIMEIT_START(corrective_smooth); | TIMEIT_START(corrective_smooth); | ||||
| #endif | #endif | ||||
| /* do the actual delta mush */ | /* do the actual delta mush */ | ||||
| smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, verts_num); | smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, verts_num); | ||||
| { | { | ||||
| uint i; | uint l_index; | ||||
| float(*tangent_spaces)[3][3]; | float(*tangent_spaces)[3][3]; | ||||
| float *tangent_weights; | |||||
| float *tangent_weights_per_vertex; | |||||
| const float scale = csmd->scale; | const float scale = csmd->scale; | ||||
| /* calloc, since values are accumulated */ | |||||
| tangent_spaces = MEM_calloc_arrayN(verts_num, sizeof(float[3][3]), __func__); | |||||
| calc_tangent_spaces(mesh, vertexCos, tangent_spaces); | tangent_spaces = MEM_malloc_arrayN(loops_num, sizeof(float[3][3]), __func__); | ||||
| tangent_weights = MEM_malloc_arrayN(loops_num, sizeof(float), __func__); | |||||
| tangent_weights_per_vertex = MEM_malloc_arrayN(loops_num, sizeof(float), __func__); | |||||
| calc_tangent_spaces( | |||||
| mesh, vertexCos, tangent_spaces, tangent_weights, tangent_weights_per_vertex); | |||||
| for (l_index = 0; l_index < loops_num; l_index++) { | |||||
| const uint v_index = mesh->mloop[l_index].v; | |||||
| const float weight = tangent_weights[l_index] / tangent_weights_per_vertex[v_index]; | |||||
| if (UNLIKELY(!(weight > 0.0f))) { | |||||
| /* Catches zero & divide by zero. */ | |||||
| continue; | |||||
| } | |||||
| for (i = 0; i < verts_num; i++) { | |||||
| float delta[3]; | float delta[3]; | ||||
| mul_v3_m3v3(delta, tangent_spaces[l_index], csmd->delta_cache.deltas[l_index]); | |||||
| #ifdef USE_TANGENT_CALC_INLINE | mul_v3_fl(delta, weight); | ||||
| calc_tangent_ortho(tangent_spaces[i]); | madd_v3_v3fl(vertexCos[v_index], delta, scale); | ||||
| #endif | |||||
| mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache.deltas[i]); | |||||
| madd_v3_v3fl(vertexCos[i], delta, scale); | |||||
| } | } | ||||
| MEM_freeN(tangent_spaces); | MEM_freeN(tangent_spaces); | ||||
| MEM_freeN(tangent_weights); | |||||
| MEM_freeN(tangent_weights_per_vertex); | |||||
| } | } | ||||
| #ifdef DEBUG_TIME | #ifdef DEBUG_TIME | ||||
| TIMEIT_END(corrective_smooth); | TIMEIT_END(corrective_smooth); | ||||
| #endif | #endif | ||||
| return; | return; | ||||
| /* when the modifier fails to execute */ | /* when the modifier fails to execute */ | ||||
| error: | error: | ||||
| MEM_SAFE_FREE(csmd->delta_cache.deltas); | MEM_SAFE_FREE(csmd->delta_cache.deltas); | ||||
| csmd->delta_cache.totverts = 0; | csmd->delta_cache.deltas_num = 0; | ||||
| } | } | ||||
| static void deformVerts(ModifierData *md, | static void deformVerts(ModifierData *md, | ||||
| const ModifierEvalContext *ctx, | const ModifierEvalContext *ctx, | ||||
| Mesh *mesh, | Mesh *mesh, | ||||
| float (*vertexCos)[3], | float (*vertexCos)[3], | ||||
| int verts_num) | int verts_num) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | static void blendRead(BlendDataReader *reader, ModifierData *md) | ||||
| CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; | CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; | ||||
| if (csmd->bind_coords) { | if (csmd->bind_coords) { | ||||
| BLO_read_float3_array(reader, (int)csmd->bind_coords_num, (float **)&csmd->bind_coords); | BLO_read_float3_array(reader, (int)csmd->bind_coords_num, (float **)&csmd->bind_coords); | ||||
| } | } | ||||
| /* runtime only */ | /* runtime only */ | ||||
| csmd->delta_cache.deltas = NULL; | csmd->delta_cache.deltas = NULL; | ||||
| csmd->delta_cache.totverts = 0; | csmd->delta_cache.deltas_num = 0; | ||||
| } | } | ||||
| ModifierTypeInfo modifierType_CorrectiveSmooth = { | ModifierTypeInfo modifierType_CorrectiveSmooth = { | ||||
| /* name */ "CorrectiveSmooth", | /* name */ "CorrectiveSmooth", | ||||
| /* structName */ "CorrectiveSmoothModifierData", | /* structName */ "CorrectiveSmoothModifierData", | ||||
| /* structSize */ sizeof(CorrectiveSmoothModifierData), | /* structSize */ sizeof(CorrectiveSmoothModifierData), | ||||
| /* srna */ &RNA_CorrectiveSmoothModifier, | /* srna */ &RNA_CorrectiveSmoothModifier, | ||||
| /* type */ eModifierTypeType_OnlyDeform, | /* type */ eModifierTypeType_OnlyDeform, | ||||
| Show All 26 Lines | |||||