From 9b6088cb9da4df1a893361997fc1a22986bf6f2e Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 16 Jul 2020 14:37:21 +0200 Subject: Simulation: Change BPH prefix to SIM In a previous commit the `physics` folder has been renamed to `simulation`. This commit updates the function/file prefix accordingly. --- source/blender/blenkernel/intern/cloth.c | 20 +- source/blender/makesrna/intern/rna_cloth.c | 10 +- source/blender/simulation/BPH_mass_spring.h | 62 - source/blender/simulation/CMakeLists.txt | 4 +- source/blender/simulation/SIM_mass_spring.h | 62 + .../blender/simulation/intern/BPH_mass_spring.cpp | 1355 -------------------- .../blender/simulation/intern/SIM_mass_spring.cpp | 1355 ++++++++++++++++++++ source/blender/simulation/intern/hair_volume.cpp | 26 +- source/blender/simulation/intern/implicit.h | 96 +- .../blender/simulation/intern/implicit_blender.c | 94 +- .../blender/simulation/intern/implicit_eigen.cpp | 70 +- 11 files changed, 1577 insertions(+), 1577 deletions(-) delete mode 100644 source/blender/simulation/BPH_mass_spring.h create mode 100644 source/blender/simulation/SIM_mass_spring.h delete mode 100644 source/blender/simulation/intern/BPH_mass_spring.cpp create mode 100644 source/blender/simulation/intern/SIM_mass_spring.cpp diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index f45cd5b679a..467bd68c631 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -47,7 +47,7 @@ #include "BKE_modifier.h" #include "BKE_pointcache.h" -#include "BPH_mass_spring.h" +#include "SIM_mass_spring.h" // #include "PIL_time.h" /* timing for debug prints */ @@ -344,12 +344,12 @@ static int do_init_cloth(Object *ob, ClothModifierData *clmd, Mesh *result, int return 0; } - BKE_cloth_solver_set_positions(clmd); + SIM_cloth_solver_set_positions(clmd); ClothSimSettings *parms = clmd->sim_parms; if (parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE && !(parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE_VOL)) { - BKE_cloth_solver_set_volume(clmd); + SIM_cloth_solver_set_volume(clmd); } clmd->clothObject->last_frame = MINFRAME - 1; @@ -404,7 +404,7 @@ static int do_step_cloth( // TIMEIT_START(cloth_step) /* call the solver. */ - ret = BPH_cloth_solve(depsgraph, ob, framenr, clmd, effectors); + ret = SIM_cloth_solve(depsgraph, ob, framenr, clmd, effectors); // TIMEIT_END(cloth_step) @@ -479,7 +479,7 @@ void clothModifier_do(ClothModifierData *clmd, if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED || (!can_simulate && cache_result == PTCACHE_READ_OLD)) { - BKE_cloth_solver_set_positions(clmd); + SIM_cloth_solver_set_positions(clmd); cloth_to_object(ob, clmd, vertexCos); BKE_ptcache_validate(cache, framenr); @@ -493,7 +493,7 @@ void clothModifier_do(ClothModifierData *clmd, return; } if (cache_result == PTCACHE_READ_OLD) { - BKE_cloth_solver_set_positions(clmd); + SIM_cloth_solver_set_positions(clmd); } else if ( /* 2.4x disabled lib, but this can be used in some cases, testing further - campbell */ @@ -537,7 +537,7 @@ void cloth_free_modifier(ClothModifierData *clmd) cloth = clmd->clothObject; if (cloth) { - BPH_cloth_solver_free(clmd); + SIM_cloth_solver_free(clmd); // Free the verts. if (cloth->verts != NULL) { @@ -619,7 +619,7 @@ void cloth_free_modifier_extern(ClothModifierData *clmd) printf("cloth_free_modifier_extern in\n"); } - BPH_cloth_solver_free(clmd); + SIM_cloth_solver_free(clmd); // Free the verts. if (cloth->verts != NULL) { @@ -919,10 +919,10 @@ static int cloth_from_object( } // init our solver - BPH_cloth_solver_init(ob, clmd); + SIM_cloth_solver_init(ob, clmd); if (!first) { - BKE_cloth_solver_set_positions(clmd); + SIM_cloth_solver_set_positions(clmd); } clmd->clothObject->bvhtree = bvhtree_build_from_cloth(clmd, clmd->coll_parms->epsilon); diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c index 594b77ea1ad..e99bd531c65 100644 --- a/source/blender/makesrna/intern/rna_cloth.c +++ b/source/blender/makesrna/intern/rna_cloth.c @@ -34,7 +34,7 @@ #include "BKE_cloth.h" #include "BKE_modifier.h" -#include "BPH_mass_spring.h" +#include "SIM_mass_spring.h" #include "WM_api.h" #include "WM_types.h" @@ -482,18 +482,18 @@ static void rna_def_cloth_solver_result(BlenderRNA *brna) PropertyRNA *prop; static const EnumPropertyItem status_items[] = { - {BPH_SOLVER_SUCCESS, "SUCCESS", 0, "Success", "Computation was successful"}, - {BPH_SOLVER_NUMERICAL_ISSUE, + {SIM_SOLVER_SUCCESS, "SUCCESS", 0, "Success", "Computation was successful"}, + {SIM_SOLVER_NUMERICAL_ISSUE, "NUMERICAL_ISSUE", 0, "Numerical Issue", "The provided data did not satisfy the prerequisites"}, - {BPH_SOLVER_NO_CONVERGENCE, + {SIM_SOLVER_NO_CONVERGENCE, "NO_CONVERGENCE", 0, "No Convergence", "Iterative procedure did not converge"}, - {BPH_SOLVER_INVALID_INPUT, + {SIM_SOLVER_INVALID_INPUT, "INVALID_INPUT", 0, "Invalid Input", diff --git a/source/blender/simulation/BPH_mass_spring.h b/source/blender/simulation/BPH_mass_spring.h deleted file mode 100644 index 5a8c78812a4..00000000000 --- a/source/blender/simulation/BPH_mass_spring.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) Blender Foundation - * All rights reserved. - */ - -/** \file - * \ingroup bph - */ - -#ifndef __BPH_MASS_SPRING_H__ -#define __BPH_MASS_SPRING_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -struct ClothModifierData; -struct Depsgraph; -struct Implicit_Data; -struct ListBase; -struct Object; - -typedef enum eMassSpringSolverStatus { - BPH_SOLVER_SUCCESS = (1 << 0), - BPH_SOLVER_NUMERICAL_ISSUE = (1 << 1), - BPH_SOLVER_NO_CONVERGENCE = (1 << 2), - BPH_SOLVER_INVALID_INPUT = (1 << 3), -} eMassSpringSolverStatus; - -struct Implicit_Data *BPH_mass_spring_solver_create(int numverts, int numsprings); -void BPH_mass_spring_solver_free(struct Implicit_Data *id); -int BPH_mass_spring_solver_numvert(struct Implicit_Data *id); - -int BPH_cloth_solver_init(struct Object *ob, struct ClothModifierData *clmd); -void BPH_cloth_solver_free(struct ClothModifierData *clmd); -int BPH_cloth_solve(struct Depsgraph *depsgraph, - struct Object *ob, - float frame, - struct ClothModifierData *clmd, - struct ListBase *effectors); -void BKE_cloth_solver_set_positions(struct ClothModifierData *clmd); -void BKE_cloth_solver_set_volume(ClothModifierData *clmd); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/source/blender/simulation/CMakeLists.txt b/source/blender/simulation/CMakeLists.txt index 10520a18513..aced9664f51 100644 --- a/source/blender/simulation/CMakeLists.txt +++ b/source/blender/simulation/CMakeLists.txt @@ -34,7 +34,7 @@ set(INC_SYS ) set(SRC - intern/BPH_mass_spring.cpp + intern/SIM_mass_spring.cpp intern/ConstrainedConjugateGradient.h intern/eigen_utils.h intern/hair_volume.cpp @@ -42,7 +42,7 @@ set(SRC intern/implicit_blender.c intern/implicit_eigen.cpp - BPH_mass_spring.h + SIM_mass_spring.h ) set(LIB diff --git a/source/blender/simulation/SIM_mass_spring.h b/source/blender/simulation/SIM_mass_spring.h new file mode 100644 index 00000000000..d30a7160fd8 --- /dev/null +++ b/source/blender/simulation/SIM_mass_spring.h @@ -0,0 +1,62 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) Blender Foundation + * All rights reserved. + */ + +/** \file + * \ingroup bph + */ + +#ifndef __SIM_MASS_SPRING_H__ +#define __SIM_MASS_SPRING_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct ClothModifierData; +struct Depsgraph; +struct Implicit_Data; +struct ListBase; +struct Object; + +typedef enum eMassSpringSolverStatus { + SIM_SOLVER_SUCCESS = (1 << 0), + SIM_SOLVER_NUMERICAL_ISSUE = (1 << 1), + SIM_SOLVER_NO_CONVERGENCE = (1 << 2), + SIM_SOLVER_INVALID_INPUT = (1 << 3), +} eMassSpringSolverStatus; + +struct Implicit_Data *SIM_mass_spring_solver_create(int numverts, int numsprings); +void SIM_mass_spring_solver_free(struct Implicit_Data *id); +int SIM_mass_spring_solver_numvert(struct Implicit_Data *id); + +int SIM_cloth_solver_init(struct Object *ob, struct ClothModifierData *clmd); +void SIM_cloth_solver_free(struct ClothModifierData *clmd); +int SIM_cloth_solve(struct Depsgraph *depsgraph, + struct Object *ob, + float frame, + struct ClothModifierData *clmd, + struct ListBase *effectors); +void SIM_cloth_solver_set_positions(struct ClothModifierData *clmd); +void SIM_cloth_solver_set_volume(ClothModifierData *clmd); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/blender/simulation/intern/BPH_mass_spring.cpp b/source/blender/simulation/intern/BPH_mass_spring.cpp deleted file mode 100644 index 051f11aa1d9..00000000000 --- a/source/blender/simulation/intern/BPH_mass_spring.cpp +++ /dev/null @@ -1,1355 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) Blender Foundation - * All rights reserved. - */ - -/** \file - * \ingroup bph - */ - -#include "MEM_guardedalloc.h" - -#include "DNA_cloth_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_force_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" - -#include "BLI_linklist.h" -#include "BLI_math.h" -#include "BLI_utildefines.h" - -#include "BKE_cloth.h" -#include "BKE_collision.h" -#include "BKE_effect.h" - -#include "BPH_mass_spring.h" -#include "implicit.h" - -#include "DEG_depsgraph.h" -#include "DEG_depsgraph_query.h" - -static float I3[3][3] = {{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}}; - -/* Number of off-diagonal non-zero matrix blocks. - * Basically there is one of these for each vertex-vertex interaction. - */ -static int cloth_count_nondiag_blocks(Cloth *cloth) -{ - LinkNode *link; - int nondiag = 0; - - for (link = cloth->springs; link; link = link->next) { - ClothSpring *spring = (ClothSpring *)link->link; - switch (spring->type) { - case CLOTH_SPRING_TYPE_BENDING_HAIR: - /* angular bending combines 3 vertices */ - nondiag += 3; - break; - - default: - /* all other springs depend on 2 vertices only */ - nondiag += 1; - break; - } - } - - return nondiag; -} - -static bool cloth_get_pressure_weights(ClothModifierData *clmd, - const MVertTri *vt, - float *r_weights) -{ - /* We have custom vertex weights for pressure. */ - if (clmd->sim_parms->vgroup_pressure > 0) { - Cloth *cloth = clmd->clothObject; - ClothVertex *verts = cloth->verts; - - for (unsigned int j = 0; j < 3; j++) { - r_weights[j] = verts[vt->tri[j]].pressure_factor; - - /* Skip the entire triangle if it has a zero weight. */ - if (r_weights[j] == 0.0f) { - return false; - } - } - } - - return true; -} - -static void cloth_calc_pressure_gradient(ClothModifierData *clmd, - const float gradient_vector[3], - float *r_vertex_pressure) -{ - Cloth *cloth = clmd->clothObject; - Implicit_Data *data = cloth->implicit; - unsigned int mvert_num = cloth->mvert_num; - float pt[3]; - - for (unsigned int i = 0; i < mvert_num; i++) { - BPH_mass_spring_get_position(data, i, pt); - r_vertex_pressure[i] = dot_v3v3(pt, gradient_vector); - } -} - -static float cloth_calc_volume(ClothModifierData *clmd) -{ - /* Calculate the (closed) cloth volume. */ - Cloth *cloth = clmd->clothObject; - const MVertTri *tri = cloth->tri; - Implicit_Data *data = cloth->implicit; - float weights[3] = {1.0f, 1.0f, 1.0f}; - float vol = 0; - - /* Early exit for hair, as it never has volume. */ - if (clmd->hairdata) { - return 0.0f; - } - - for (unsigned int i = 0; i < cloth->primitive_num; i++) { - const MVertTri *vt = &tri[i]; - - if (cloth_get_pressure_weights(clmd, vt, weights)) { - vol += BPH_tri_tetra_volume_signed_6x(data, vt->tri[0], vt->tri[1], vt->tri[2]); - } - } - - /* We need to divide by 6 to get the actual volume. */ - vol = vol / 6.0f; - - return vol; -} - -static float cloth_calc_rest_volume(ClothModifierData *clmd) -{ - /* Calculate the (closed) cloth volume. */ - Cloth *cloth = clmd->clothObject; - const MVertTri *tri = cloth->tri; - const ClothVertex *v = cloth->verts; - float weights[3] = {1.0f, 1.0f, 1.0f}; - float vol = 0; - - /* Early exit for hair, as it never has volume. */ - if (clmd->hairdata) { - return 0.0f; - } - - for (unsigned int i = 0; i < cloth->primitive_num; i++) { - const MVertTri *vt = &tri[i]; - - if (cloth_get_pressure_weights(clmd, vt, weights)) { - vol += volume_tri_tetrahedron_signed_v3_6x( - v[vt->tri[0]].xrest, v[vt->tri[1]].xrest, v[vt->tri[2]].xrest); - } - } - - /* We need to divide by 6 to get the actual volume. */ - vol = vol / 6.0f; - - return vol; -} - -static float cloth_calc_average_pressure(ClothModifierData *clmd, const float *vertex_pressure) -{ - Cloth *cloth = clmd->clothObject; - const MVertTri *tri = cloth->tri; - Implicit_Data *data = cloth->implicit; - float weights[3] = {1.0f, 1.0f, 1.0f}; - float total_force = 0; - float total_area = 0; - - for (unsigned int i = 0; i < cloth->primitive_num; i++) { - const MVertTri *vt = &tri[i]; - - if (cloth_get_pressure_weights(clmd, vt, weights)) { - float area = BPH_tri_area(data, vt->tri[0], vt->tri[1], vt->tri[2]); - - total_force += (vertex_pressure[vt->tri[0]] + vertex_pressure[vt->tri[1]] + - vertex_pressure[vt->tri[2]]) * - area / 3.0f; - total_area += area; - } - } - - return total_force / total_area; -} - -int BPH_cloth_solver_init(Object *UNUSED(ob), ClothModifierData *clmd) -{ - Cloth *cloth = clmd->clothObject; - ClothVertex *verts = cloth->verts; - const float ZERO[3] = {0.0f, 0.0f, 0.0f}; - Implicit_Data *id; - unsigned int i, nondiag; - - nondiag = cloth_count_nondiag_blocks(cloth); - cloth->implicit = id = BPH_mass_spring_solver_create(cloth->mvert_num, nondiag); - - for (i = 0; i < cloth->mvert_num; i++) { - BPH_mass_spring_set_vertex_mass(id, i, verts[i].mass); - } - - for (i = 0; i < cloth->mvert_num; i++) { - BPH_mass_spring_set_motion_state(id, i, verts[i].x, ZERO); - } - - return 1; -} - -void BPH_cloth_solver_free(ClothModifierData *clmd) -{ - Cloth *cloth = clmd->clothObject; - - if (cloth->implicit) { - BPH_mass_spring_solver_free(cloth->implicit); - cloth->implicit = NULL; - } -} - -void BKE_cloth_solver_set_positions(ClothModifierData *clmd) -{ - Cloth *cloth = clmd->clothObject; - ClothVertex *verts = cloth->verts; - unsigned int mvert_num = cloth->mvert_num, i; - ClothHairData *cloth_hairdata = clmd->hairdata; - Implicit_Data *id = cloth->implicit; - - for (i = 0; i < mvert_num; i++) { - if (cloth_hairdata) { - ClothHairData *root = &cloth_hairdata[i]; - BPH_mass_spring_set_rest_transform(id, i, root->rot); - } - else { - BPH_mass_spring_set_rest_transform(id, i, I3); - } - - BPH_mass_spring_set_motion_state(id, i, verts[i].x, verts[i].v); - } -} - -void BKE_cloth_solver_set_volume(ClothModifierData *clmd) -{ - Cloth *cloth = clmd->clothObject; - - cloth->initial_mesh_volume = cloth_calc_rest_volume(clmd); -} - -/* Init constraint matrix - * This is part of the modified CG method suggested by Baraff/Witkin in - * "Large Steps in Cloth Simulation" (Siggraph 1998) - */ -static void cloth_setup_constraints(ClothModifierData *clmd) -{ - Cloth *cloth = clmd->clothObject; - Implicit_Data *data = cloth->implicit; - ClothVertex *verts = cloth->verts; - int mvert_num = cloth->mvert_num; - int v; - - const float ZERO[3] = {0.0f, 0.0f, 0.0f}; - - BPH_mass_spring_clear_constraints(data); - - for (v = 0; v < mvert_num; v++) { - if (verts[v].flags & CLOTH_VERT_FLAG_PINNED) { - /* pinned vertex constraints */ - BPH_mass_spring_add_constraint_ndof0(data, v, ZERO); /* velocity is defined externally */ - } - - verts[v].impulse_count = 0; - } -} - -/* computes where the cloth would be if it were subject to perfectly stiff edges - * (edge distance constraints) in a lagrangian solver. then add forces to help - * guide the implicit solver to that state. this function is called after - * collisions*/ -static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), - ClothModifierData *clmd, - float (*initial_cos)[3], - float UNUSED(step), - float dt) -{ - Cloth *cloth = clmd->clothObject; - float(*cos)[3] = (float(*)[3])MEM_callocN(sizeof(float[3]) * cloth->mvert_num, - "cos cloth_calc_helper_forces"); - float *masses = (float *)MEM_callocN(sizeof(float) * cloth->mvert_num, - "cos cloth_calc_helper_forces"); - LinkNode *node; - ClothSpring *spring; - ClothVertex *cv; - int i, steps; - - cv = cloth->verts; - for (i = 0; i < cloth->mvert_num; i++, cv++) { - copy_v3_v3(cos[i], cv->tx); - - if (cv->goal == 1.0f || len_squared_v3v3(initial_cos[i], cv->tx) != 0.0f) { - masses[i] = 1e+10; - } - else { - masses[i] = cv->mass; - } - } - - steps = 55; - for (i = 0; i < steps; i++) { - for (node = cloth->springs; node; node = node->next) { - /* ClothVertex *cv1, *cv2; */ /* UNUSED */ - int v1, v2; - float len, c, l, vec[3]; - - spring = (ClothSpring *)node->link; - if (spring->type != CLOTH_SPRING_TYPE_STRUCTURAL && - spring->type != CLOTH_SPRING_TYPE_SHEAR) { - continue; - } - - v1 = spring->ij; - v2 = spring->kl; - /* cv1 = cloth->verts + v1; */ /* UNUSED */ - /* cv2 = cloth->verts + v2; */ /* UNUSED */ - len = len_v3v3(cos[v1], cos[v2]); - - sub_v3_v3v3(vec, cos[v1], cos[v2]); - normalize_v3(vec); - - c = (len - spring->restlen); - if (c == 0.0f) { - continue; - } - - l = c / ((1.0f / masses[v1]) + (1.0f / masses[v2])); - - mul_v3_fl(vec, -(1.0f / masses[v1]) * l); - add_v3_v3(cos[v1], vec); - - sub_v3_v3v3(vec, cos[v2], cos[v1]); - normalize_v3(vec); - - mul_v3_fl(vec, -(1.0f / masses[v2]) * l); - add_v3_v3(cos[v2], vec); - } - } - - cv = cloth->verts; - for (i = 0; i < cloth->mvert_num; i++, cv++) { - float vec[3]; - - /*compute forces*/ - sub_v3_v3v3(vec, cos[i], cv->tx); - mul_v3_fl(vec, cv->mass * dt * 20.0f); - add_v3_v3(cv->tv, vec); - // copy_v3_v3(cv->tx, cos[i]); - } - - MEM_freeN(cos); - MEM_freeN(masses); - - return 1; -} - -BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s) -{ - Cloth *cloth = clmd->clothObject; - ClothSimSettings *parms = clmd->sim_parms; - Implicit_Data *data = cloth->implicit; - bool using_angular = parms->bending_model == CLOTH_BENDING_ANGULAR; - bool resist_compress = (parms->flags & CLOTH_SIMSETTINGS_FLAG_RESIST_SPRING_COMPRESS) && - !using_angular; - - s->flags &= ~CLOTH_SPRING_FLAG_NEEDED; - - /* Calculate force of bending springs. */ - if ((s->type & CLOTH_SPRING_TYPE_BENDING) && using_angular) { -#ifdef CLOTH_FORCE_SPRING_BEND - float k, scaling; - - s->flags |= CLOTH_SPRING_FLAG_NEEDED; - - scaling = parms->bending + s->ang_stiffness * fabsf(parms->max_bend - parms->bending); - k = scaling * s->restlen * - 0.1f; /* Multiplying by 0.1, just to scale the forces to more reasonable values. */ - - BPH_mass_spring_force_spring_angular( - data, s->ij, s->kl, s->pa, s->pb, s->la, s->lb, s->restang, k, parms->bending_damping); -#endif - } - - /* Calculate force of structural + shear springs. */ - if (s->type & - (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SEWING | CLOTH_SPRING_TYPE_INTERNAL)) { -#ifdef CLOTH_FORCE_SPRING_STRUCTURAL - float k_tension, scaling_tension; - - s->flags |= CLOTH_SPRING_FLAG_NEEDED; - - scaling_tension = parms->tension + - s->lin_stiffness * fabsf(parms->max_tension - parms->tension); - k_tension = scaling_tension / (parms->avg_spring_len + FLT_EPSILON); - - if (s->type & CLOTH_SPRING_TYPE_SEWING) { - /* TODO: verify, half verified (couldn't see error) - * sewing springs usually have a large distance at first so clamp the force so we don't get - * tunneling through collision objects. */ - BPH_mass_spring_force_spring_linear(data, - s->ij, - s->kl, - s->restlen, - k_tension, - parms->tension_damp, - 0.0f, - 0.0f, - false, - false, - parms->max_sewing); - } - else if (s->type & CLOTH_SPRING_TYPE_STRUCTURAL) { - float k_compression, scaling_compression; - scaling_compression = parms->compression + - s->lin_stiffness * fabsf(parms->max_compression - parms->compression); - k_compression = scaling_compression / (parms->avg_spring_len + FLT_EPSILON); - - BPH_mass_spring_force_spring_linear(data, - s->ij, - s->kl, - s->restlen, - k_tension, - parms->tension_damp, - k_compression, - parms->compression_damp, - resist_compress, - using_angular, - 0.0f); - } - else { - /* CLOTH_SPRING_TYPE_INTERNAL */ - BLI_assert(s->type & CLOTH_SPRING_TYPE_INTERNAL); - - scaling_tension = parms->internal_tension + - s->lin_stiffness * - fabsf(parms->max_internal_tension - parms->internal_tension); - k_tension = scaling_tension / (parms->avg_spring_len + FLT_EPSILON); - float scaling_compression = parms->internal_compression + - s->lin_stiffness * fabsf(parms->max_internal_compression - - parms->internal_compression); - float k_compression = scaling_compression / (parms->avg_spring_len + FLT_EPSILON); - - float k_tension_damp = parms->tension_damp; - float k_compression_damp = parms->compression_damp; - - if (k_tension == 0.0f) { - /* No damping so it behaves as if no tension spring was there at all. */ - k_tension_damp = 0.0f; - } - - if (k_compression == 0.0f) { - /* No damping so it behaves as if no compression spring was there at all. */ - k_compression_damp = 0.0f; - } - - BPH_mass_spring_force_spring_linear(data, - s->ij, - s->kl, - s->restlen, - k_tension, - k_tension_damp, - k_compression, - k_compression_damp, - resist_compress, - using_angular, - 0.0f); - } -#endif - } - else if (s->type & CLOTH_SPRING_TYPE_SHEAR) { -#ifdef CLOTH_FORCE_SPRING_SHEAR - float k, scaling; - - s->flags |= CLOTH_SPRING_FLAG_NEEDED; - - scaling = parms->shear + s->lin_stiffness * fabsf(parms->max_shear - parms->shear); - k = scaling / (parms->avg_spring_len + FLT_EPSILON); - - BPH_mass_spring_force_spring_linear(data, - s->ij, - s->kl, - s->restlen, - k, - parms->shear_damp, - 0.0f, - 0.0f, - resist_compress, - false, - 0.0f); -#endif - } - else if (s->type & CLOTH_SPRING_TYPE_BENDING) { /* calculate force of bending springs */ -#ifdef CLOTH_FORCE_SPRING_BEND - float kb, cb, scaling; - - s->flags |= CLOTH_SPRING_FLAG_NEEDED; - - scaling = parms->bending + s->lin_stiffness * fabsf(parms->max_bend - parms->bending); - kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON)); - - // Fix for [#45084] for cloth stiffness must have cb proportional to kb - cb = kb * parms->bending_damping; - - BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb); -#endif - } - else if (s->type & CLOTH_SPRING_TYPE_BENDING_HAIR) { -#ifdef CLOTH_FORCE_SPRING_BEND - float kb, cb, scaling; - - s->flags |= CLOTH_SPRING_FLAG_NEEDED; - - /* XXX WARNING: angular bending springs for hair apply stiffness factor as an overall factor, - * unlike cloth springs! this is crap, but needed due to cloth/hair mixing ... max_bend factor - * is not even used for hair, so ... - */ - scaling = s->lin_stiffness * parms->bending; - kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON)); - - // Fix for [#45084] for cloth stiffness must have cb proportional to kb - cb = kb * parms->bending_damping; - - /* XXX assuming same restlen for ij and jk segments here, - * this can be done correctly for hair later. */ - BPH_mass_spring_force_spring_bending_hair(data, s->ij, s->kl, s->mn, s->target, kb, cb); - -# if 0 - { - float x_kl[3], x_mn[3], v[3], d[3]; - - BPH_mass_spring_get_motion_state(data, s->kl, x_kl, v); - BPH_mass_spring_get_motion_state(data, s->mn, x_mn, v); - - BKE_sim_debug_data_add_dot(clmd->debug_data, x_kl, 0.9, 0.9, 0.9, "target", 7980, s->kl); - BKE_sim_debug_data_add_line( - clmd->debug_data, x_kl, x_mn, 0.8, 0.8, 0.8, "target", 7981, s->kl); - - copy_v3_v3(d, s->target); - BKE_sim_debug_data_add_vector( - clmd->debug_data, x_kl, d, 0.8, 0.8, 0.2, "target", 7982, s->kl); - - // copy_v3_v3(d, s->target_ij); - // BKE_sim_debug_data_add_vector(clmd->debug_data, x, d, 1, 0.4, 0.4, "target", 7983, s->kl); - } -# endif -#endif - } -} - -static void hair_get_boundbox(ClothModifierData *clmd, float gmin[3], float gmax[3]) -{ - Cloth *cloth = clmd->clothObject; - Implicit_Data *data = cloth->implicit; - unsigned int mvert_num = cloth->mvert_num; - int i; - - INIT_MINMAX(gmin, gmax); - for (i = 0; i < mvert_num; i++) { - float x[3]; - BPH_mass_spring_get_motion_state(data, i, x, NULL); - DO_MINMAX(x, gmin, gmax); - } -} - -static void cloth_calc_force( - Scene *scene, ClothModifierData *clmd, float UNUSED(frame), ListBase *effectors, float time) -{ - /* Collect forces and derivatives: F, dFdX, dFdV */ - Cloth *cloth = clmd->clothObject; - ClothSimSettings *parms = clmd->sim_parms; - Implicit_Data *data = cloth->implicit; - unsigned int i = 0; - float drag = clmd->sim_parms->Cvi * 0.01f; /* viscosity of air scaled in percent */ - float gravity[3] = {0.0f, 0.0f, 0.0f}; - const MVertTri *tri = cloth->tri; - unsigned int mvert_num = cloth->mvert_num; - ClothVertex *vert; - -#ifdef CLOTH_FORCE_GRAVITY - /* global acceleration (gravitation) */ - if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { - /* scale gravity force */ - mul_v3_v3fl(gravity, - scene->physics_settings.gravity, - 0.001f * clmd->sim_parms->effector_weights->global_gravity); - } - - vert = cloth->verts; - for (i = 0; i < cloth->mvert_num; i++, vert++) { - BPH_mass_spring_force_gravity(data, i, vert->mass, gravity); - - /* Vertex goal springs */ - if ((!(vert->flags & CLOTH_VERT_FLAG_PINNED)) && (vert->goal > FLT_EPSILON)) { - float goal_x[3], goal_v[3]; - float k; - - /* divide by time_scale to prevent goal vertices' delta locations from being multiplied */ - interp_v3_v3v3(goal_x, vert->xold, vert->xconst, time / clmd->sim_parms->time_scale); - sub_v3_v3v3(goal_v, vert->xconst, vert->xold); /* distance covered over dt==1 */ - - k = vert->goal * clmd->sim_parms->goalspring / - (clmd->sim_parms->avg_spring_len + FLT_EPSILON); - - BPH_mass_spring_force_spring_goal( - data, i, goal_x, goal_v, k, clmd->sim_parms->goalfrict * 0.01f); - } - } -#endif - - /* cloth_calc_volume_force(clmd); */ - -#ifdef CLOTH_FORCE_DRAG - BPH_mass_spring_force_drag(data, drag); -#endif - /* handle pressure forces (making sure that this never gets computed for hair). */ - if ((parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE) && (clmd->hairdata == NULL)) { - /* The difference in pressure between the inside and outside of the mesh.*/ - float pressure_difference = 0.0f; - float volume_factor = 1.0f; - - float init_vol; - if (parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE_VOL) { - init_vol = clmd->sim_parms->target_volume; - } - else { - init_vol = cloth->initial_mesh_volume; - } - - /* Check if we need to calculate the volume of the mesh. */ - if (init_vol > 1E-6f) { - float f; - float vol = cloth_calc_volume(clmd); - - /* If the volume is the same don't apply any pressure. */ - volume_factor = init_vol / vol; - pressure_difference = volume_factor - 1; - - /* Calculate an artificial maximum value for cloth pressure. */ - f = fabs(clmd->sim_parms->uniform_pressure_force) + 200.0f; - - /* Clamp the cloth pressure to the calculated maximum value. */ - CLAMP_MAX(pressure_difference, f); - } - - pressure_difference += clmd->sim_parms->uniform_pressure_force; - pressure_difference *= clmd->sim_parms->pressure_factor; - - /* Compute the hydrostatic pressure gradient if enabled. */ - float fluid_density = clmd->sim_parms->fluid_density * 1000; /* kg/l -> kg/m3 */ - float *hydrostatic_pressure = NULL; - - if (fabs(fluid_density) > 1e-6f) { - float hydrostatic_vector[3]; - copy_v3_v3(hydrostatic_vector, gravity); - - /* When the fluid is inside the object, factor in the acceleration of - * the object into the pressure field, as gravity is indistinguishable - * from acceleration from the inside. */ - if (fluid_density > 0) { - sub_v3_v3(hydrostatic_vector, cloth->average_acceleration); - - /* Preserve the total mass by scaling density to match the change in volume. */ - fluid_density *= volume_factor; - } - - mul_v3_fl(hydrostatic_vector, fluid_density); - - /* Compute an array of per-vertex hydrostatic pressure, and subtract the average. */ - hydrostatic_pressure = (float *)MEM_mallocN(sizeof(float) * mvert_num, - "hydrostatic pressure gradient"); - - cloth_calc_pressure_gradient(clmd, hydrostatic_vector, hydrostatic_pressure); - - pressure_difference -= cloth_calc_average_pressure(clmd, hydrostatic_pressure); - } - - /* Apply pressure. */ - if (hydrostatic_pressure || fabs(pressure_difference) > 1E-6f) { - float weights[3] = {1.0f, 1.0f, 1.0f}; - - for (i = 0; i < cloth->primitive_num; i++) { - const MVertTri *vt = &tri[i]; - - if (cloth_get_pressure_weights(clmd, vt, weights)) { - BPH_mass_spring_force_pressure(data, - vt->tri[0], - vt->tri[1], - vt->tri[2], - pressure_difference, - hydrostatic_pressure, - weights); - } - } - } - - if (hydrostatic_pressure) { - MEM_freeN(hydrostatic_pressure); - } - } - - /* handle external forces like wind */ - if (effectors) { - bool is_not_hair = (clmd->hairdata == NULL) && (cloth->primitive_num > 0); - bool has_wind = false, has_force = false; - - /* cache per-vertex forces to avoid redundant calculation */ - float(*winvec)[3] = (float(*)[3])MEM_callocN(sizeof(float[3]) * mvert_num * 2, - "effector forces"); - float(*forcevec)[3] = is_not_hair ? winvec + mvert_num : winvec; - - for (i = 0; i < cloth->mvert_num; i++) { - float x[3], v[3]; - EffectedPoint epoint; - - BPH_mass_spring_get_motion_state(data, i, x, v); - pd_point_from_loc(scene, x, v, i, &epoint); - BKE_effectors_apply(effectors, - NULL, - clmd->sim_parms->effector_weights, - &epoint, - forcevec[i], - winvec[i], - NULL); - - has_wind = has_wind || !is_zero_v3(winvec[i]); - has_force = has_force || !is_zero_v3(forcevec[i]); - } - - /* Hair has only edges. */ - if (is_not_hair) { - for (i = 0; i < cloth->primitive_num; i++) { - const MVertTri *vt = &tri[i]; - if (has_wind) { - BPH_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec); - } - if (has_force) { - BPH_mass_spring_force_face_extern(data, vt->tri[0], vt->tri[1], vt->tri[2], forcevec); - } - } - } - else { -#if 0 - ClothHairData *hairdata = clmd->hairdata; - ClothHairData *hair_ij, *hair_kl; - - for (LinkNode *link = cloth->springs; link; link = link->next) { - ClothSpring *spring = (ClothSpring *)link->link; - if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) { - if (hairdata) { - hair_ij = &hairdata[spring->ij]; - hair_kl = &hairdata[spring->kl]; - BPH_mass_spring_force_edge_wind( - data, spring->ij, spring->kl, hair_ij->radius, hair_kl->radius, winvec); - } - else { - BPH_mass_spring_force_edge_wind(data, spring->ij, spring->kl, 1.0f, 1.0f, winvec); - } - } - } -#else - ClothHairData *hairdata = clmd->hairdata; - - vert = cloth->verts; - for (i = 0; i < cloth->mvert_num; i++, vert++) { - if (hairdata) { - ClothHairData *hair = &hairdata[i]; - BPH_mass_spring_force_vertex_wind(data, i, hair->radius, winvec); - } - else { - BPH_mass_spring_force_vertex_wind(data, i, 1.0f, winvec); - } - } -#endif - } - - MEM_freeN(winvec); - } - - // calculate spring forces - for (LinkNode *link = cloth->springs; link; link = link->next) { - ClothSpring *spring = (ClothSpring *)link->link; - // only handle active springs - if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE)) { - cloth_calc_spring_force(clmd, spring); - } - } -} - -/* returns vertexes' motion state */ -BLI_INLINE void cloth_get_grid_location(Implicit_Data *data, - float cell_scale, - const float cell_offset[3], - int index, - float x[3], - float v[3]) -{ - BPH_mass_spring_get_position(data, index, x); - BPH_mass_spring_get_new_velocity(data, index, v); - - mul_v3_fl(x, cell_scale); - add_v3_v3(x, cell_offset); -} - -/* returns next spring forming a continuous hair sequence */ -BLI_INLINE LinkNode *hair_spring_next(LinkNode *spring_link) -{ - ClothSpring *spring = (ClothSpring *)spring_link->link; - LinkNode *next = spring_link->next; - if (next) { - ClothSpring *next_spring = (ClothSpring *)next->link; - if (next_spring->type == CLOTH_SPRING_TYPE_STRUCTURAL && next_spring->kl == spring->ij) { - return next; - } - } - return NULL; -} - -/* XXX this is nasty: cloth meshes do not explicitly store - * the order of hair segments! - * We have to rely on the spring build function for now, - * which adds structural springs in reverse order: - * (3,4), (2,3), (1,2) - * This is currently the only way to figure out hair geometry inside this code ... - */ -static LinkNode *cloth_continuum_add_hair_segments(HairGrid *grid, - const float cell_scale, - const float cell_offset[3], - Cloth *cloth, - LinkNode *spring_link) -{ - Implicit_Data *data = cloth->implicit; - LinkNode *next_spring_link = NULL; /* return value */ - ClothSpring *spring1, *spring2, *spring3; - // ClothVertex *verts = cloth->verts; - // ClothVertex *vert3, *vert4; - float x1[3], v1[3], x2[3], v2[3], x3[3], v3[3], x4[3], v4[3]; - float dir1[3], dir2[3], dir3[3]; - - spring1 = NULL; - spring2 = NULL; - spring3 = (ClothSpring *)spring_link->link; - - zero_v3(x1); - zero_v3(v1); - zero_v3(dir1); - zero_v3(x2); - zero_v3(v2); - zero_v3(dir2); - - // vert3 = &verts[spring3->kl]; - cloth_get_grid_location(data, cell_scale, cell_offset, spring3->kl, x3, v3); - // vert4 = &verts[spring3->ij]; - cloth_get_grid_location(data, cell_scale, cell_offset, spring3->ij, x4, v4); - sub_v3_v3v3(dir3, x4, x3); - normalize_v3(dir3); - - while (spring_link) { - /* move on */ - spring1 = spring2; - spring2 = spring3; - - // vert3 = vert4; - - copy_v3_v3(x1, x2); - copy_v3_v3(v1, v2); - copy_v3_v3(x2, x3); - copy_v3_v3(v2, v3); - copy_v3_v3(x3, x4); - copy_v3_v3(v3, v4); - - copy_v3_v3(dir1, dir2); - copy_v3_v3(dir2, dir3); - - /* read next segment */ - next_spring_link = spring_link->next; - spring_link = hair_spring_next(spring_link); - - if (spring_link) { - spring3 = (ClothSpring *)spring_link->link; - // vert4 = &verts[spring3->ij]; - cloth_get_grid_location(data, cell_scale, cell_offset, spring3->ij, x4, v4); - sub_v3_v3v3(dir3, x4, x3); - normalize_v3(dir3); - } - else { - spring3 = NULL; - // vert4 = NULL; - zero_v3(x4); - zero_v3(v4); - zero_v3(dir3); - } - - BPH_hair_volume_add_segment( - grid, x1, v1, x2, v2, x3, v3, x4, v4, spring1 ? dir1 : NULL, dir2, spring3 ? dir3 : NULL); - } - - return next_spring_link; -} - -static void cloth_continuum_fill_grid(HairGrid *grid, Cloth *cloth) -{ -#if 0 - Implicit_Data *data = cloth->implicit; - int mvert_num = cloth->mvert_num; - ClothVertex *vert; - int i; - - for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) { - float x[3], v[3]; - - cloth_get_vertex_motion_state(data, vert, x, v); - BPH_hair_volume_add_vertex(grid, x, v); - } -#else - LinkNode *link; - float cellsize, gmin[3], cell_scale, cell_offset[3]; - - /* scale and offset for transforming vertex locations into grid space - * (cell size is 0..1, gmin becomes origin) - */ - BPH_hair_volume_grid_geometry(grid, &cellsize, NULL, gmin, NULL); - cell_scale = cellsize > 0.0f ? 1.0f / cellsize : 0.0f; - mul_v3_v3fl(cell_offset, gmin, cell_scale); - negate_v3(cell_offset); - - link = cloth->springs; - while (link) { - ClothSpring *spring = (ClothSpring *)link->link; - if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) { - link = cloth_continuum_add_hair_segments(grid, cell_scale, cell_offset, cloth, link); - } - else { - link = link->next; - } - } -#endif - BPH_hair_volume_normalize_vertex_grid(grid); -} - -static void cloth_continuum_step(ClothModifierData *clmd, float dt) -{ - ClothSimSettings *parms = clmd->sim_parms; - Cloth *cloth = clmd->clothObject; - Implicit_Data *data = cloth->implicit; - int mvert_num = cloth->mvert_num; - ClothVertex *vert; - - const float fluid_factor = 0.95f; /* blend between PIC and FLIP methods */ - float smoothfac = parms->velocity_smooth; - /* XXX FIXME arbitrary factor!!! this should be based on some intuitive value instead, - * like number of hairs per cell and time decay instead of "strength" - */ - float density_target = parms->density_target; - float density_strength = parms->density_strength; - float gmin[3], gmax[3]; - int i; - - /* clear grid info */ - zero_v3_int(clmd->hair_grid_res); - zero_v3(clmd->hair_grid_min); - zero_v3(clmd->hair_grid_max); - clmd->hair_grid_cellsize = 0.0f; - - hair_get_boundbox(clmd, gmin, gmax); - - /* gather velocities & density */ - if (smoothfac > 0.0f || density_strength > 0.0f) { - HairGrid *grid = BPH_hair_volume_create_vertex_grid( - clmd->sim_parms->voxel_cell_size, gmin, gmax); - - cloth_continuum_fill_grid(grid, cloth); - - /* main hair continuum solver */ - BPH_hair_volume_solve_divergence(grid, dt, density_target, density_strength); - - for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) { - float x[3], v[3], nv[3]; - - /* calculate volumetric velocity influence */ - BPH_mass_spring_get_position(data, i, x); - BPH_mass_spring_get_new_velocity(data, i, v); - - BPH_hair_volume_grid_velocity(grid, x, v, fluid_factor, nv); - - interp_v3_v3v3(nv, v, nv, smoothfac); - - /* apply on hair data */ - BPH_mass_spring_set_new_velocity(data, i, nv); - } - - /* store basic grid info in the modifier data */ - BPH_hair_volume_grid_geometry(grid, - &clmd->hair_grid_cellsize, - clmd->hair_grid_res, - clmd->hair_grid_min, - clmd->hair_grid_max); - -#if 0 /* DEBUG hair velocity vector field */ - { - const int size = 64; - int i, j; - float offset[3], a[3], b[3]; - const int axis = 0; - const float shift = 0.0f; - - copy_v3_v3(offset, clmd->hair_grid_min); - zero_v3(a); - zero_v3(b); - - offset[axis] = shift * clmd->hair_grid_cellsize; - a[(axis + 1) % 3] = clmd->hair_grid_max[(axis + 1) % 3] - - clmd->hair_grid_min[(axis + 1) % 3]; - b[(axis + 2) % 3] = clmd->hair_grid_max[(axis + 2) % 3] - - clmd->hair_grid_min[(axis + 2) % 3]; - - BKE_sim_debug_data_clear_category(clmd->debug_data, "grid velocity"); - for (j = 0; j < size; j++) { - for (i = 0; i < size; i++) { - float x[3], v[3], gvel[3], gvel_smooth[3], gdensity; - - madd_v3_v3v3fl(x, offset, a, (float)i / (float)(size - 1)); - madd_v3_v3fl(x, b, (float)j / (float)(size - 1)); - zero_v3(v); - - BPH_hair_volume_grid_interpolate(grid, x, &gdensity, gvel, gvel_smooth, NULL, NULL); - - // BKE_sim_debug_data_add_circle( - // clmd->debug_data, x, gdensity, 0.7, 0.3, 1, - // "grid density", i, j, 3111); - if (!is_zero_v3(gvel) || !is_zero_v3(gvel_smooth)) { - float dvel[3]; - sub_v3_v3v3(dvel, gvel_smooth, gvel); - // BKE_sim_debug_data_add_vector( - // clmd->debug_data, x, gvel, 0.4, 0, 1, - // "grid velocity", i, j, 3112); - // BKE_sim_debug_data_add_vector( - // clmd->debug_data, x, gvel_smooth, 0.6, 1, 1, - // "grid velocity", i, j, 3113); - BKE_sim_debug_data_add_vector( - clmd->debug_data, x, dvel, 0.4, 1, 0.7, "grid velocity", i, j, 3114); -# if 0 - if (gdensity > 0.0f) { - float col0[3] = {0.0, 0.0, 0.0}; - float col1[3] = {0.0, 1.0, 0.0}; - float col[3]; - - interp_v3_v3v3(col, col0, col1, - CLAMPIS(gdensity * clmd->sim_parms->density_strength, 0.0, 1.0)); - // BKE_sim_debug_data_add_circle( - // clmd->debug_data, x, gdensity * clmd->sim_parms->density_strength, 0, 1, 0.4, - // "grid velocity", i, j, 3115); - // BKE_sim_debug_data_add_dot( - // clmd->debug_data, x, col[0], col[1], col[2], - // "grid velocity", i, j, 3115); - BKE_sim_debug_data_add_circle( - clmd->debug_data, x, 0.01f, col[0], col[1], col[2], "grid velocity", i, j, 3115); - } -# endif - } - } - } - } -#endif - - BPH_hair_volume_free_vertex_grid(grid); - } -} - -#if 0 -static void cloth_calc_volume_force(ClothModifierData *clmd) -{ - ClothSimSettings *parms = clmd->sim_parms; - Cloth *cloth = clmd->clothObject; - Implicit_Data *data = cloth->implicit; - int mvert_num = cloth->mvert_num; - ClothVertex *vert; - - /* 2.0f is an experimental value that seems to give good results */ - float smoothfac = 2.0f * parms->velocity_smooth; - float collfac = 2.0f * parms->collider_friction; - float pressfac = parms->pressure; - float minpress = parms->pressure_threshold; - float gmin[3], gmax[3]; - int i; - - hair_get_boundbox(clmd, gmin, gmax); - - /* gather velocities & density */ - if (smoothfac > 0.0f || pressfac > 0.0f) { - HairVertexGrid *vertex_grid = BPH_hair_volume_create_vertex_grid( - clmd->sim_parms->voxel_res, gmin, gmax); - - vert = cloth->verts; - for (i = 0; i < mvert_num; i++, vert++) { - float x[3], v[3]; - - if (vert->solver_index < 0) { - copy_v3_v3(x, vert->x); - copy_v3_v3(v, vert->v); - } - else { - BPH_mass_spring_get_motion_state(data, vert->solver_index, x, v); - } - BPH_hair_volume_add_vertex(vertex_grid, x, v); - } - BPH_hair_volume_normalize_vertex_grid(vertex_grid); - - vert = cloth->verts; - for (i = 0; i < mvert_num; i++, vert++) { - float x[3], v[3], f[3], dfdx[3][3], dfdv[3][3]; - - if (vert->solver_index < 0) { - continue; - } - - /* calculate volumetric forces */ - BPH_mass_spring_get_motion_state(data, vert->solver_index, x, v); - BPH_hair_volume_vertex_grid_forces( - vertex_grid, x, v, smoothfac, pressfac, minpress, f, dfdx, dfdv); - /* apply on hair data */ - BPH_mass_spring_force_extern(data, vert->solver_index, f, dfdx, dfdv); - } - - BPH_hair_volume_free_vertex_grid(vertex_grid); - } -} -#endif - -static void cloth_calc_average_acceleration(ClothModifierData *clmd, float dt) -{ - Cloth *cloth = clmd->clothObject; - Implicit_Data *data = cloth->implicit; - int i, mvert_num = cloth->mvert_num; - float total[3] = {0.0f, 0.0f, 0.0f}; - - for (i = 0; i < mvert_num; i++) { - float v[3], nv[3]; - - BPH_mass_spring_get_velocity(data, i, v); - BPH_mass_spring_get_new_velocity(data, i, nv); - - sub_v3_v3(nv, v); - add_v3_v3(total, nv); - } - - mul_v3_fl(total, 1.0f / dt / mvert_num); - - /* Smooth the data using a running average to prevent instability. - * This is effectively an abstraction of the wave propagation speed in fluid. */ - interp_v3_v3v3(cloth->average_acceleration, total, cloth->average_acceleration, powf(0.25f, dt)); -} - -static void cloth_solve_collisions( - Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt) -{ - Cloth *cloth = clmd->clothObject; - Implicit_Data *id = cloth->implicit; - ClothVertex *verts = cloth->verts; - int mvert_num = cloth->mvert_num; - const float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale); - int i; - - if (!(clmd->coll_parms->flags & - (CLOTH_COLLSETTINGS_FLAG_ENABLED | CLOTH_COLLSETTINGS_FLAG_SELF))) { - return; - } - - if (!clmd->clothObject->bvhtree) { - return; - } - - BPH_mass_spring_solve_positions(id, dt); - - /* Update verts to current positions. */ - for (i = 0; i < mvert_num; i++) { - BPH_mass_spring_get_new_position(id, i, verts[i].tx); - - sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold); - zero_v3(verts[i].dcvel); - } - - if (cloth_bvh_collision(depsgraph, - ob, - clmd, - step / clmd->sim_parms->timescale, - dt / clmd->sim_parms->timescale)) { - for (i = 0; i < mvert_num; i++) { - if ((clmd->sim_parms->vgroup_mass > 0) && (verts[i].flags & CLOTH_VERT_FLAG_PINNED)) { - continue; - } - - BPH_mass_spring_get_new_velocity(id, i, verts[i].tv); - madd_v3_v3fl(verts[i].tv, verts[i].dcvel, time_multiplier); - BPH_mass_spring_set_new_velocity(id, i, verts[i].tv); - } - } -} - -static void cloth_clear_result(ClothModifierData *clmd) -{ - ClothSolverResult *sres = clmd->solver_result; - - sres->status = 0; - sres->max_error = sres->min_error = sres->avg_error = 0.0f; - sres->max_iterations = sres->min_iterations = 0; - sres->avg_iterations = 0.0f; -} - -static void cloth_record_result(ClothModifierData *clmd, ImplicitSolverResult *result, float dt) -{ - ClothSolverResult *sres = clmd->solver_result; - - if (sres->status) { /* already initialized ? */ - /* error only makes sense for successful iterations */ - if (result->status == BPH_SOLVER_SUCCESS) { - sres->min_error = min_ff(sres->min_error, result->error); - sres->max_error = max_ff(sres->max_error, result->error); - sres->avg_error += result->error * dt; - } - - sres->min_iterations = min_ii(sres->min_iterations, result->iterations); - sres->max_iterations = max_ii(sres->max_iterations, result->iterations); - sres->avg_iterations += (float)result->iterations * dt; - } - else { - /* error only makes sense for successful iterations */ - if (result->status == BPH_SOLVER_SUCCESS) { - sres->min_error = sres->max_error = result->error; - sres->avg_error += result->error * dt; - } - - sres->min_iterations = sres->max_iterations = result->iterations; - sres->avg_iterations += (float)result->iterations * dt; - } - - sres->status |= result->status; -} - -int BPH_cloth_solve( - Depsgraph *depsgraph, Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors) -{ - /* Hair currently is a cloth sim in disguise ... - * Collision detection and volumetrics work differently then. - * Bad design, TODO - */ - Scene *scene = DEG_get_evaluated_scene(depsgraph); - const bool is_hair = (clmd->hairdata != NULL); - - unsigned int i = 0; - float step = 0.0f, tf = clmd->sim_parms->timescale; - Cloth *cloth = clmd->clothObject; - ClothVertex *verts = cloth->verts /*, *cv*/; - unsigned int mvert_num = cloth->mvert_num; - float dt = clmd->sim_parms->dt * clmd->sim_parms->timescale; - Implicit_Data *id = cloth->implicit; - - /* Hydrostatic pressure gradient of the fluid inside the object is affected by acceleration. */ - bool use_acceleration = (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE) && - (clmd->sim_parms->fluid_density > 0); - - BKE_sim_debug_data_clear_category("collision"); - - if (!clmd->solver_result) { - clmd->solver_result = (ClothSolverResult *)MEM_callocN(sizeof(ClothSolverResult), - "cloth solver result"); - } - cloth_clear_result(clmd); - - if (clmd->sim_parms->vgroup_mass > 0) { /* Do goal stuff. */ - for (i = 0; i < mvert_num; i++) { - // update velocities with constrained velocities from pinned verts - if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) { - float v[3]; - sub_v3_v3v3(v, verts[i].xconst, verts[i].xold); - // mul_v3_fl(v, clmd->sim_parms->stepsPerFrame); - /* divide by time_scale to prevent constrained velocities from being multiplied */ - mul_v3_fl(v, 1.0f / clmd->sim_parms->time_scale); - BPH_mass_spring_set_velocity(id, i, v); - } - } - } - - if (!use_acceleration) { - zero_v3(cloth->average_acceleration); - } - - while (step < tf) { - ImplicitSolverResult result; - - /* setup vertex constraints for pinned vertices */ - cloth_setup_constraints(clmd); - - /* initialize forces to zero */ - BPH_mass_spring_clear_forces(id); - - // calculate forces - cloth_calc_force(scene, clmd, frame, effectors, step); - - // calculate new velocity and position - BPH_mass_spring_solve_velocities(id, dt, &result); - cloth_record_result(clmd, &result, dt); - - /* Calculate collision impulses. */ - cloth_solve_collisions(depsgraph, ob, clmd, step, dt); - - if (is_hair) { - cloth_continuum_step(clmd, dt); - } - - if (use_acceleration) { - cloth_calc_average_acceleration(clmd, dt); - } - - BPH_mass_spring_solve_positions(id, dt); - BPH_mass_spring_apply_result(id); - - /* move pinned verts to correct position */ - for (i = 0; i < mvert_num; i++) { - if (clmd->sim_parms->vgroup_mass > 0) { - if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) { - float x[3]; - /* divide by time_scale to prevent pinned vertices' - * delta locations from being multiplied */ - interp_v3_v3v3( - x, verts[i].xold, verts[i].xconst, (step + dt) / clmd->sim_parms->time_scale); - BPH_mass_spring_set_position(id, i, x); - } - } - - BPH_mass_spring_get_motion_state(id, i, verts[i].txold, NULL); - } - - step += dt; - } - - /* copy results back to cloth data */ - for (i = 0; i < mvert_num; i++) { - BPH_mass_spring_get_motion_state(id, i, verts[i].x, verts[i].v); - copy_v3_v3(verts[i].txold, verts[i].x); - } - - return 1; -} diff --git a/source/blender/simulation/intern/SIM_mass_spring.cpp b/source/blender/simulation/intern/SIM_mass_spring.cpp new file mode 100644 index 00000000000..4834d6d351c --- /dev/null +++ b/source/blender/simulation/intern/SIM_mass_spring.cpp @@ -0,0 +1,1355 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) Blender Foundation + * All rights reserved. + */ + +/** \file + * \ingroup bph + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_cloth_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_force_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BLI_linklist.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_cloth.h" +#include "BKE_collision.h" +#include "BKE_effect.h" + +#include "SIM_mass_spring.h" +#include "implicit.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +static float I3[3][3] = {{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}}; + +/* Number of off-diagonal non-zero matrix blocks. + * Basically there is one of these for each vertex-vertex interaction. + */ +static int cloth_count_nondiag_blocks(Cloth *cloth) +{ + LinkNode *link; + int nondiag = 0; + + for (link = cloth->springs; link; link = link->next) { + ClothSpring *spring = (ClothSpring *)link->link; + switch (spring->type) { + case CLOTH_SPRING_TYPE_BENDING_HAIR: + /* angular bending combines 3 vertices */ + nondiag += 3; + break; + + default: + /* all other springs depend on 2 vertices only */ + nondiag += 1; + break; + } + } + + return nondiag; +} + +static bool cloth_get_pressure_weights(ClothModifierData *clmd, + const MVertTri *vt, + float *r_weights) +{ + /* We have custom vertex weights for pressure. */ + if (clmd->sim_parms->vgroup_pressure > 0) { + Cloth *cloth = clmd->clothObject; + ClothVertex *verts = cloth->verts; + + for (unsigned int j = 0; j < 3; j++) { + r_weights[j] = verts[vt->tri[j]].pressure_factor; + + /* Skip the entire triangle if it has a zero weight. */ + if (r_weights[j] == 0.0f) { + return false; + } + } + } + + return true; +} + +static void cloth_calc_pressure_gradient(ClothModifierData *clmd, + const float gradient_vector[3], + float *r_vertex_pressure) +{ + Cloth *cloth = clmd->clothObject; + Implicit_Data *data = cloth->implicit; + unsigned int mvert_num = cloth->mvert_num; + float pt[3]; + + for (unsigned int i = 0; i < mvert_num; i++) { + SIM_mass_spring_get_position(data, i, pt); + r_vertex_pressure[i] = dot_v3v3(pt, gradient_vector); + } +} + +static float cloth_calc_volume(ClothModifierData *clmd) +{ + /* Calculate the (closed) cloth volume. */ + Cloth *cloth = clmd->clothObject; + const MVertTri *tri = cloth->tri; + Implicit_Data *data = cloth->implicit; + float weights[3] = {1.0f, 1.0f, 1.0f}; + float vol = 0; + + /* Early exit for hair, as it never has volume. */ + if (clmd->hairdata) { + return 0.0f; + } + + for (unsigned int i = 0; i < cloth->primitive_num; i++) { + const MVertTri *vt = &tri[i]; + + if (cloth_get_pressure_weights(clmd, vt, weights)) { + vol += SIM_tri_tetra_volume_signed_6x(data, vt->tri[0], vt->tri[1], vt->tri[2]); + } + } + + /* We need to divide by 6 to get the actual volume. */ + vol = vol / 6.0f; + + return vol; +} + +static float cloth_calc_rest_volume(ClothModifierData *clmd) +{ + /* Calculate the (closed) cloth volume. */ + Cloth *cloth = clmd->clothObject; + const MVertTri *tri = cloth->tri; + const ClothVertex *v = cloth->verts; + float weights[3] = {1.0f, 1.0f, 1.0f}; + float vol = 0; + + /* Early exit for hair, as it never has volume. */ + if (clmd->hairdata) { + return 0.0f; + } + + for (unsigned int i = 0; i < cloth->primitive_num; i++) { + const MVertTri *vt = &tri[i]; + + if (cloth_get_pressure_weights(clmd, vt, weights)) { + vol += volume_tri_tetrahedron_signed_v3_6x( + v[vt->tri[0]].xrest, v[vt->tri[1]].xrest, v[vt->tri[2]].xrest); + } + } + + /* We need to divide by 6 to get the actual volume. */ + vol = vol / 6.0f; + + return vol; +} + +static float cloth_calc_average_pressure(ClothModifierData *clmd, const float *vertex_pressure) +{ + Cloth *cloth = clmd->clothObject; + const MVertTri *tri = cloth->tri; + Implicit_Data *data = cloth->implicit; + float weights[3] = {1.0f, 1.0f, 1.0f}; + float total_force = 0; + float total_area = 0; + + for (unsigned int i = 0; i < cloth->primitive_num; i++) { + const MVertTri *vt = &tri[i]; + + if (cloth_get_pressure_weights(clmd, vt, weights)) { + float area = SIM_tri_area(data, vt->tri[0], vt->tri[1], vt->tri[2]); + + total_force += (vertex_pressure[vt->tri[0]] + vertex_pressure[vt->tri[1]] + + vertex_pressure[vt->tri[2]]) * + area / 3.0f; + total_area += area; + } + } + + return total_force / total_area; +} + +int SIM_cloth_solver_init(Object *UNUSED(ob), ClothModifierData *clmd) +{ + Cloth *cloth = clmd->clothObject; + ClothVertex *verts = cloth->verts; + const float ZERO[3] = {0.0f, 0.0f, 0.0f}; + Implicit_Data *id; + unsigned int i, nondiag; + + nondiag = cloth_count_nondiag_blocks(cloth); + cloth->implicit = id = SIM_mass_spring_solver_create(cloth->mvert_num, nondiag); + + for (i = 0; i < cloth->mvert_num; i++) { + SIM_mass_spring_set_vertex_mass(id, i, verts[i].mass); + } + + for (i = 0; i < cloth->mvert_num; i++) { + SIM_mass_spring_set_motion_state(id, i, verts[i].x, ZERO); + } + + return 1; +} + +void SIM_cloth_solver_free(ClothModifierData *clmd) +{ + Cloth *cloth = clmd->clothObject; + + if (cloth->implicit) { + SIM_mass_spring_solver_free(cloth->implicit); + cloth->implicit = NULL; + } +} + +void SIM_cloth_solver_set_positions(ClothModifierData *clmd) +{ + Cloth *cloth = clmd->clothObject; + ClothVertex *verts = cloth->verts; + unsigned int mvert_num = cloth->mvert_num, i; + ClothHairData *cloth_hairdata = clmd->hairdata; + Implicit_Data *id = cloth->implicit; + + for (i = 0; i < mvert_num; i++) { + if (cloth_hairdata) { + ClothHairData *root = &cloth_hairdata[i]; + SIM_mass_spring_set_rest_transform(id, i, root->rot); + } + else { + SIM_mass_spring_set_rest_transform(id, i, I3); + } + + SIM_mass_spring_set_motion_state(id, i, verts[i].x, verts[i].v); + } +} + +void SIM_cloth_solver_set_volume(ClothModifierData *clmd) +{ + Cloth *cloth = clmd->clothObject; + + cloth->initial_mesh_volume = cloth_calc_rest_volume(clmd); +} + +/* Init constraint matrix + * This is part of the modified CG method suggested by Baraff/Witkin in + * "Large Steps in Cloth Simulation" (Siggraph 1998) + */ +static void cloth_setup_constraints(ClothModifierData *clmd) +{ + Cloth *cloth = clmd->clothObject; + Implicit_Data *data = cloth->implicit; + ClothVertex *verts = cloth->verts; + int mvert_num = cloth->mvert_num; + int v; + + const float ZERO[3] = {0.0f, 0.0f, 0.0f}; + + SIM_mass_spring_clear_constraints(data); + + for (v = 0; v < mvert_num; v++) { + if (verts[v].flags & CLOTH_VERT_FLAG_PINNED) { + /* pinned vertex constraints */ + SIM_mass_spring_add_constraint_ndof0(data, v, ZERO); /* velocity is defined externally */ + } + + verts[v].impulse_count = 0; + } +} + +/* computes where the cloth would be if it were subject to perfectly stiff edges + * (edge distance constraints) in a lagrangian solver. then add forces to help + * guide the implicit solver to that state. this function is called after + * collisions*/ +static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), + ClothModifierData *clmd, + float (*initial_cos)[3], + float UNUSED(step), + float dt) +{ + Cloth *cloth = clmd->clothObject; + float(*cos)[3] = (float(*)[3])MEM_callocN(sizeof(float[3]) * cloth->mvert_num, + "cos cloth_calc_helper_forces"); + float *masses = (float *)MEM_callocN(sizeof(float) * cloth->mvert_num, + "cos cloth_calc_helper_forces"); + LinkNode *node; + ClothSpring *spring; + ClothVertex *cv; + int i, steps; + + cv = cloth->verts; + for (i = 0; i < cloth->mvert_num; i++, cv++) { + copy_v3_v3(cos[i], cv->tx); + + if (cv->goal == 1.0f || len_squared_v3v3(initial_cos[i], cv->tx) != 0.0f) { + masses[i] = 1e+10; + } + else { + masses[i] = cv->mass; + } + } + + steps = 55; + for (i = 0; i < steps; i++) { + for (node = cloth->springs; node; node = node->next) { + /* ClothVertex *cv1, *cv2; */ /* UNUSED */ + int v1, v2; + float len, c, l, vec[3]; + + spring = (ClothSpring *)node->link; + if (spring->type != CLOTH_SPRING_TYPE_STRUCTURAL && + spring->type != CLOTH_SPRING_TYPE_SHEAR) { + continue; + } + + v1 = spring->ij; + v2 = spring->kl; + /* cv1 = cloth->verts + v1; */ /* UNUSED */ + /* cv2 = cloth->verts + v2; */ /* UNUSED */ + len = len_v3v3(cos[v1], cos[v2]); + + sub_v3_v3v3(vec, cos[v1], cos[v2]); + normalize_v3(vec); + + c = (len - spring->restlen); + if (c == 0.0f) { + continue; + } + + l = c / ((1.0f / masses[v1]) + (1.0f / masses[v2])); + + mul_v3_fl(vec, -(1.0f / masses[v1]) * l); + add_v3_v3(cos[v1], vec); + + sub_v3_v3v3(vec, cos[v2], cos[v1]); + normalize_v3(vec); + + mul_v3_fl(vec, -(1.0f / masses[v2]) * l); + add_v3_v3(cos[v2], vec); + } + } + + cv = cloth->verts; + for (i = 0; i < cloth->mvert_num; i++, cv++) { + float vec[3]; + + /*compute forces*/ + sub_v3_v3v3(vec, cos[i], cv->tx); + mul_v3_fl(vec, cv->mass * dt * 20.0f); + add_v3_v3(cv->tv, vec); + // copy_v3_v3(cv->tx, cos[i]); + } + + MEM_freeN(cos); + MEM_freeN(masses); + + return 1; +} + +BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s) +{ + Cloth *cloth = clmd->clothObject; + ClothSimSettings *parms = clmd->sim_parms; + Implicit_Data *data = cloth->implicit; + bool using_angular = parms->bending_model == CLOTH_BENDING_ANGULAR; + bool resist_compress = (parms->flags & CLOTH_SIMSETTINGS_FLAG_RESIST_SPRING_COMPRESS) && + !using_angular; + + s->flags &= ~CLOTH_SPRING_FLAG_NEEDED; + + /* Calculate force of bending springs. */ + if ((s->type & CLOTH_SPRING_TYPE_BENDING) && using_angular) { +#ifdef CLOTH_FORCE_SPRING_BEND + float k, scaling; + + s->flags |= CLOTH_SPRING_FLAG_NEEDED; + + scaling = parms->bending + s->ang_stiffness * fabsf(parms->max_bend - parms->bending); + k = scaling * s->restlen * + 0.1f; /* Multiplying by 0.1, just to scale the forces to more reasonable values. */ + + SIM_mass_spring_force_spring_angular( + data, s->ij, s->kl, s->pa, s->pb, s->la, s->lb, s->restang, k, parms->bending_damping); +#endif + } + + /* Calculate force of structural + shear springs. */ + if (s->type & + (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SEWING | CLOTH_SPRING_TYPE_INTERNAL)) { +#ifdef CLOTH_FORCE_SPRING_STRUCTURAL + float k_tension, scaling_tension; + + s->flags |= CLOTH_SPRING_FLAG_NEEDED; + + scaling_tension = parms->tension + + s->lin_stiffness * fabsf(parms->max_tension - parms->tension); + k_tension = scaling_tension / (parms->avg_spring_len + FLT_EPSILON); + + if (s->type & CLOTH_SPRING_TYPE_SEWING) { + /* TODO: verify, half verified (couldn't see error) + * sewing springs usually have a large distance at first so clamp the force so we don't get + * tunneling through collision objects. */ + SIM_mass_spring_force_spring_linear(data, + s->ij, + s->kl, + s->restlen, + k_tension, + parms->tension_damp, + 0.0f, + 0.0f, + false, + false, + parms->max_sewing); + } + else if (s->type & CLOTH_SPRING_TYPE_STRUCTURAL) { + float k_compression, scaling_compression; + scaling_compression = parms->compression + + s->lin_stiffness * fabsf(parms->max_compression - parms->compression); + k_compression = scaling_compression / (parms->avg_spring_len + FLT_EPSILON); + + SIM_mass_spring_force_spring_linear(data, + s->ij, + s->kl, + s->restlen, + k_tension, + parms->tension_damp, + k_compression, + parms->compression_damp, + resist_compress, + using_angular, + 0.0f); + } + else { + /* CLOTH_SPRING_TYPE_INTERNAL */ + BLI_assert(s->type & CLOTH_SPRING_TYPE_INTERNAL); + + scaling_tension = parms->internal_tension + + s->lin_stiffness * + fabsf(parms->max_internal_tension - parms->internal_tension); + k_tension = scaling_tension / (parms->avg_spring_len + FLT_EPSILON); + float scaling_compression = parms->internal_compression + + s->lin_stiffness * fabsf(parms->max_internal_compression - + parms->internal_compression); + float k_compression = scaling_compression / (parms->avg_spring_len + FLT_EPSILON); + + float k_tension_damp = parms->tension_damp; + float k_compression_damp = parms->compression_damp; + + if (k_tension == 0.0f) { + /* No damping so it behaves as if no tension spring was there at all. */ + k_tension_damp = 0.0f; + } + + if (k_compression == 0.0f) { + /* No damping so it behaves as if no compression spring was there at all. */ + k_compression_damp = 0.0f; + } + + SIM_mass_spring_force_spring_linear(data, + s->ij, + s->kl, + s->restlen, + k_tension, + k_tension_damp, + k_compression, + k_compression_damp, + resist_compress, + using_angular, + 0.0f); + } +#endif + } + else if (s->type & CLOTH_SPRING_TYPE_SHEAR) { +#ifdef CLOTH_FORCE_SPRING_SHEAR + float k, scaling; + + s->flags |= CLOTH_SPRING_FLAG_NEEDED; + + scaling = parms->shear + s->lin_stiffness * fabsf(parms->max_shear - parms->shear); + k = scaling / (parms->avg_spring_len + FLT_EPSILON); + + SIM_mass_spring_force_spring_linear(data, + s->ij, + s->kl, + s->restlen, + k, + parms->shear_damp, + 0.0f, + 0.0f, + resist_compress, + false, + 0.0f); +#endif + } + else if (s->type & CLOTH_SPRING_TYPE_BENDING) { /* calculate force of bending springs */ +#ifdef CLOTH_FORCE_SPRING_BEND + float kb, cb, scaling; + + s->flags |= CLOTH_SPRING_FLAG_NEEDED; + + scaling = parms->bending + s->lin_stiffness * fabsf(parms->max_bend - parms->bending); + kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON)); + + // Fix for [#45084] for cloth stiffness must have cb proportional to kb + cb = kb * parms->bending_damping; + + SIM_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb); +#endif + } + else if (s->type & CLOTH_SPRING_TYPE_BENDING_HAIR) { +#ifdef CLOTH_FORCE_SPRING_BEND + float kb, cb, scaling; + + s->flags |= CLOTH_SPRING_FLAG_NEEDED; + + /* XXX WARNING: angular bending springs for hair apply stiffness factor as an overall factor, + * unlike cloth springs! this is crap, but needed due to cloth/hair mixing ... max_bend factor + * is not even used for hair, so ... + */ + scaling = s->lin_stiffness * parms->bending; + kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON)); + + // Fix for [#45084] for cloth stiffness must have cb proportional to kb + cb = kb * parms->bending_damping; + + /* XXX assuming same restlen for ij and jk segments here, + * this can be done correctly for hair later. */ + SIM_mass_spring_force_spring_bending_hair(data, s->ij, s->kl, s->mn, s->target, kb, cb); + +# if 0 + { + float x_kl[3], x_mn[3], v[3], d[3]; + + SIM_mass_spring_get_motion_state(data, s->kl, x_kl, v); + SIM_mass_spring_get_motion_state(data, s->mn, x_mn, v); + + BKE_sim_debug_data_add_dot(clmd->debug_data, x_kl, 0.9, 0.9, 0.9, "target", 7980, s->kl); + BKE_sim_debug_data_add_line( + clmd->debug_data, x_kl, x_mn, 0.8, 0.8, 0.8, "target", 7981, s->kl); + + copy_v3_v3(d, s->target); + BKE_sim_debug_data_add_vector( + clmd->debug_data, x_kl, d, 0.8, 0.8, 0.2, "target", 7982, s->kl); + + // copy_v3_v3(d, s->target_ij); + // BKE_sim_debug_data_add_vector(clmd->debug_data, x, d, 1, 0.4, 0.4, "target", 7983, s->kl); + } +# endif +#endif + } +} + +static void hair_get_boundbox(ClothModifierData *clmd, float gmin[3], float gmax[3]) +{ + Cloth *cloth = clmd->clothObject; + Implicit_Data *data = cloth->implicit; + unsigned int mvert_num = cloth->mvert_num; + int i; + + INIT_MINMAX(gmin, gmax); + for (i = 0; i < mvert_num; i++) { + float x[3]; + SIM_mass_spring_get_motion_state(data, i, x, NULL); + DO_MINMAX(x, gmin, gmax); + } +} + +static void cloth_calc_force( + Scene *scene, ClothModifierData *clmd, float UNUSED(frame), ListBase *effectors, float time) +{ + /* Collect forces and derivatives: F, dFdX, dFdV */ + Cloth *cloth = clmd->clothObject; + ClothSimSettings *parms = clmd->sim_parms; + Implicit_Data *data = cloth->implicit; + unsigned int i = 0; + float drag = clmd->sim_parms->Cvi * 0.01f; /* viscosity of air scaled in percent */ + float gravity[3] = {0.0f, 0.0f, 0.0f}; + const MVertTri *tri = cloth->tri; + unsigned int mvert_num = cloth->mvert_num; + ClothVertex *vert; + +#ifdef CLOTH_FORCE_GRAVITY + /* global acceleration (gravitation) */ + if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { + /* scale gravity force */ + mul_v3_v3fl(gravity, + scene->physics_settings.gravity, + 0.001f * clmd->sim_parms->effector_weights->global_gravity); + } + + vert = cloth->verts; + for (i = 0; i < cloth->mvert_num; i++, vert++) { + SIM_mass_spring_force_gravity(data, i, vert->mass, gravity); + + /* Vertex goal springs */ + if ((!(vert->flags & CLOTH_VERT_FLAG_PINNED)) && (vert->goal > FLT_EPSILON)) { + float goal_x[3], goal_v[3]; + float k; + + /* divide by time_scale to prevent goal vertices' delta locations from being multiplied */ + interp_v3_v3v3(goal_x, vert->xold, vert->xconst, time / clmd->sim_parms->time_scale); + sub_v3_v3v3(goal_v, vert->xconst, vert->xold); /* distance covered over dt==1 */ + + k = vert->goal * clmd->sim_parms->goalspring / + (clmd->sim_parms->avg_spring_len + FLT_EPSILON); + + SIM_mass_spring_force_spring_goal( + data, i, goal_x, goal_v, k, clmd->sim_parms->goalfrict * 0.01f); + } + } +#endif + + /* cloth_calc_volume_force(clmd); */ + +#ifdef CLOTH_FORCE_DRAG + SIM_mass_spring_force_drag(data, drag); +#endif + /* handle pressure forces (making sure that this never gets computed for hair). */ + if ((parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE) && (clmd->hairdata == NULL)) { + /* The difference in pressure between the inside and outside of the mesh.*/ + float pressure_difference = 0.0f; + float volume_factor = 1.0f; + + float init_vol; + if (parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE_VOL) { + init_vol = clmd->sim_parms->target_volume; + } + else { + init_vol = cloth->initial_mesh_volume; + } + + /* Check if we need to calculate the volume of the mesh. */ + if (init_vol > 1E-6f) { + float f; + float vol = cloth_calc_volume(clmd); + + /* If the volume is the same don't apply any pressure. */ + volume_factor = init_vol / vol; + pressure_difference = volume_factor - 1; + + /* Calculate an artificial maximum value for cloth pressure. */ + f = fabs(clmd->sim_parms->uniform_pressure_force) + 200.0f; + + /* Clamp the cloth pressure to the calculated maximum value. */ + CLAMP_MAX(pressure_difference, f); + } + + pressure_difference += clmd->sim_parms->uniform_pressure_force; + pressure_difference *= clmd->sim_parms->pressure_factor; + + /* Compute the hydrostatic pressure gradient if enabled. */ + float fluid_density = clmd->sim_parms->fluid_density * 1000; /* kg/l -> kg/m3 */ + float *hydrostatic_pressure = NULL; + + if (fabs(fluid_density) > 1e-6f) { + float hydrostatic_vector[3]; + copy_v3_v3(hydrostatic_vector, gravity); + + /* When the fluid is inside the object, factor in the acceleration of + * the object into the pressure field, as gravity is indistinguishable + * from acceleration from the inside. */ + if (fluid_density > 0) { + sub_v3_v3(hydrostatic_vector, cloth->average_acceleration); + + /* Preserve the total mass by scaling density to match the change in volume. */ + fluid_density *= volume_factor; + } + + mul_v3_fl(hydrostatic_vector, fluid_density); + + /* Compute an array of per-vertex hydrostatic pressure, and subtract the average. */ + hydrostatic_pressure = (float *)MEM_mallocN(sizeof(float) * mvert_num, + "hydrostatic pressure gradient"); + + cloth_calc_pressure_gradient(clmd, hydrostatic_vector, hydrostatic_pressure); + + pressure_difference -= cloth_calc_average_pressure(clmd, hydrostatic_pressure); + } + + /* Apply pressure. */ + if (hydrostatic_pressure || fabs(pressure_difference) > 1E-6f) { + float weights[3] = {1.0f, 1.0f, 1.0f}; + + for (i = 0; i < cloth->primitive_num; i++) { + const MVertTri *vt = &tri[i]; + + if (cloth_get_pressure_weights(clmd, vt, weights)) { + SIM_mass_spring_force_pressure(data, + vt->tri[0], + vt->tri[1], + vt->tri[2], + pressure_difference, + hydrostatic_pressure, + weights); + } + } + } + + if (hydrostatic_pressure) { + MEM_freeN(hydrostatic_pressure); + } + } + + /* handle external forces like wind */ + if (effectors) { + bool is_not_hair = (clmd->hairdata == NULL) && (cloth->primitive_num > 0); + bool has_wind = false, has_force = false; + + /* cache per-vertex forces to avoid redundant calculation */ + float(*winvec)[3] = (float(*)[3])MEM_callocN(sizeof(float[3]) * mvert_num * 2, + "effector forces"); + float(*forcevec)[3] = is_not_hair ? winvec + mvert_num : winvec; + + for (i = 0; i < cloth->mvert_num; i++) { + float x[3], v[3]; + EffectedPoint epoint; + + SIM_mass_spring_get_motion_state(data, i, x, v); + pd_point_from_loc(scene, x, v, i, &epoint); + BKE_effectors_apply(effectors, + NULL, + clmd->sim_parms->effector_weights, + &epoint, + forcevec[i], + winvec[i], + NULL); + + has_wind = has_wind || !is_zero_v3(winvec[i]); + has_force = has_force || !is_zero_v3(forcevec[i]); + } + + /* Hair has only edges. */ + if (is_not_hair) { + for (i = 0; i < cloth->primitive_num; i++) { + const MVertTri *vt = &tri[i]; + if (has_wind) { + SIM_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec); + } + if (has_force) { + SIM_mass_spring_force_face_extern(data, vt->tri[0], vt->tri[1], vt->tri[2], forcevec); + } + } + } + else { +#if 0 + ClothHairData *hairdata = clmd->hairdata; + ClothHairData *hair_ij, *hair_kl; + + for (LinkNode *link = cloth->springs; link; link = link->next) { + ClothSpring *spring = (ClothSpring *)link->link; + if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) { + if (hairdata) { + hair_ij = &hairdata[spring->ij]; + hair_kl = &hairdata[spring->kl]; + SIM_mass_spring_force_edge_wind( + data, spring->ij, spring->kl, hair_ij->radius, hair_kl->radius, winvec); + } + else { + SIM_mass_spring_force_edge_wind(data, spring->ij, spring->kl, 1.0f, 1.0f, winvec); + } + } + } +#else + ClothHairData *hairdata = clmd->hairdata; + + vert = cloth->verts; + for (i = 0; i < cloth->mvert_num; i++, vert++) { + if (hairdata) { + ClothHairData *hair = &hairdata[i]; + SIM_mass_spring_force_vertex_wind(data, i, hair->radius, winvec); + } + else { + SIM_mass_spring_force_vertex_wind(data, i, 1.0f, winvec); + } + } +#endif + } + + MEM_freeN(winvec); + } + + // calculate spring forces + for (LinkNode *link = cloth->springs; link; link = link->next) { + ClothSpring *spring = (ClothSpring *)link->link; + // only handle active springs + if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE)) { + cloth_calc_spring_force(clmd, spring); + } + } +} + +/* returns vertexes' motion state */ +BLI_INLINE void cloth_get_grid_location(Implicit_Data *data, + float cell_scale, + const float cell_offset[3], + int index, + float x[3], + float v[3]) +{ + SIM_mass_spring_get_position(data, index, x); + SIM_mass_spring_get_new_velocity(data, index, v); + + mul_v3_fl(x, cell_scale); + add_v3_v3(x, cell_offset); +} + +/* returns next spring forming a continuous hair sequence */ +BLI_INLINE LinkNode *hair_spring_next(LinkNode *spring_link) +{ + ClothSpring *spring = (ClothSpring *)spring_link->link; + LinkNode *next = spring_link->next; + if (next) { + ClothSpring *next_spring = (ClothSpring *)next->link; + if (next_spring->type == CLOTH_SPRING_TYPE_STRUCTURAL && next_spring->kl == spring->ij) { + return next; + } + } + return NULL; +} + +/* XXX this is nasty: cloth meshes do not explicitly store + * the order of hair segments! + * We have to rely on the spring build function for now, + * which adds structural springs in reverse order: + * (3,4), (2,3), (1,2) + * This is currently the only way to figure out hair geometry inside this code ... + */ +static LinkNode *cloth_continuum_add_hair_segments(HairGrid *grid, + const float cell_scale, + const float cell_offset[3], + Cloth *cloth, + LinkNode *spring_link) +{ + Implicit_Data *data = cloth->implicit; + LinkNode *next_spring_link = NULL; /* return value */ + ClothSpring *spring1, *spring2, *spring3; + // ClothVertex *verts = cloth->verts; + // ClothVertex *vert3, *vert4; + float x1[3], v1[3], x2[3], v2[3], x3[3], v3[3], x4[3], v4[3]; + float dir1[3], dir2[3], dir3[3]; + + spring1 = NULL; + spring2 = NULL; + spring3 = (ClothSpring *)spring_link->link; + + zero_v3(x1); + zero_v3(v1); + zero_v3(dir1); + zero_v3(x2); + zero_v3(v2); + zero_v3(dir2); + + // vert3 = &verts[spring3->kl]; + cloth_get_grid_location(data, cell_scale, cell_offset, spring3->kl, x3, v3); + // vert4 = &verts[spring3->ij]; + cloth_get_grid_location(data, cell_scale, cell_offset, spring3->ij, x4, v4); + sub_v3_v3v3(dir3, x4, x3); + normalize_v3(dir3); + + while (spring_link) { + /* move on */ + spring1 = spring2; + spring2 = spring3; + + // vert3 = vert4; + + copy_v3_v3(x1, x2); + copy_v3_v3(v1, v2); + copy_v3_v3(x2, x3); + copy_v3_v3(v2, v3); + copy_v3_v3(x3, x4); + copy_v3_v3(v3, v4); + + copy_v3_v3(dir1, dir2); + copy_v3_v3(dir2, dir3); + + /* read next segment */ + next_spring_link = spring_link->next; + spring_link = hair_spring_next(spring_link); + + if (spring_link) { + spring3 = (ClothSpring *)spring_link->link; + // vert4 = &verts[spring3->ij]; + cloth_get_grid_location(data, cell_scale, cell_offset, spring3->ij, x4, v4); + sub_v3_v3v3(dir3, x4, x3); + normalize_v3(dir3); + } + else { + spring3 = NULL; + // vert4 = NULL; + zero_v3(x4); + zero_v3(v4); + zero_v3(dir3); + } + + SIM_hair_volume_add_segment( + grid, x1, v1, x2, v2, x3, v3, x4, v4, spring1 ? dir1 : NULL, dir2, spring3 ? dir3 : NULL); + } + + return next_spring_link; +} + +static void cloth_continuum_fill_grid(HairGrid *grid, Cloth *cloth) +{ +#if 0 + Implicit_Data *data = cloth->implicit; + int mvert_num = cloth->mvert_num; + ClothVertex *vert; + int i; + + for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) { + float x[3], v[3]; + + cloth_get_vertex_motion_state(data, vert, x, v); + SIM_hair_volume_add_vertex(grid, x, v); + } +#else + LinkNode *link; + float cellsize, gmin[3], cell_scale, cell_offset[3]; + + /* scale and offset for transforming vertex locations into grid space + * (cell size is 0..1, gmin becomes origin) + */ + SIM_hair_volume_grid_geometry(grid, &cellsize, NULL, gmin, NULL); + cell_scale = cellsize > 0.0f ? 1.0f / cellsize : 0.0f; + mul_v3_v3fl(cell_offset, gmin, cell_scale); + negate_v3(cell_offset); + + link = cloth->springs; + while (link) { + ClothSpring *spring = (ClothSpring *)link->link; + if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) { + link = cloth_continuum_add_hair_segments(grid, cell_scale, cell_offset, cloth, link); + } + else { + link = link->next; + } + } +#endif + SIM_hair_volume_normalize_vertex_grid(grid); +} + +static void cloth_continuum_step(ClothModifierData *clmd, float dt) +{ + ClothSimSettings *parms = clmd->sim_parms; + Cloth *cloth = clmd->clothObject; + Implicit_Data *data = cloth->implicit; + int mvert_num = cloth->mvert_num; + ClothVertex *vert; + + const float fluid_factor = 0.95f; /* blend between PIC and FLIP methods */ + float smoothfac = parms->velocity_smooth; + /* XXX FIXME arbitrary factor!!! this should be based on some intuitive value instead, + * like number of hairs per cell and time decay instead of "strength" + */ + float density_target = parms->density_target; + float density_strength = parms->density_strength; + float gmin[3], gmax[3]; + int i; + + /* clear grid info */ + zero_v3_int(clmd->hair_grid_res); + zero_v3(clmd->hair_grid_min); + zero_v3(clmd->hair_grid_max); + clmd->hair_grid_cellsize = 0.0f; + + hair_get_boundbox(clmd, gmin, gmax); + + /* gather velocities & density */ + if (smoothfac > 0.0f || density_strength > 0.0f) { + HairGrid *grid = SIM_hair_volume_create_vertex_grid( + clmd->sim_parms->voxel_cell_size, gmin, gmax); + + cloth_continuum_fill_grid(grid, cloth); + + /* main hair continuum solver */ + SIM_hair_volume_solve_divergence(grid, dt, density_target, density_strength); + + for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) { + float x[3], v[3], nv[3]; + + /* calculate volumetric velocity influence */ + SIM_mass_spring_get_position(data, i, x); + SIM_mass_spring_get_new_velocity(data, i, v); + + SIM_hair_volume_grid_velocity(grid, x, v, fluid_factor, nv); + + interp_v3_v3v3(nv, v, nv, smoothfac); + + /* apply on hair data */ + SIM_mass_spring_set_new_velocity(data, i, nv); + } + + /* store basic grid info in the modifier data */ + SIM_hair_volume_grid_geometry(grid, + &clmd->hair_grid_cellsize, + clmd->hair_grid_res, + clmd->hair_grid_min, + clmd->hair_grid_max); + +#if 0 /* DEBUG hair velocity vector field */ + { + const int size = 64; + int i, j; + float offset[3], a[3], b[3]; + const int axis = 0; + const float shift = 0.0f; + + copy_v3_v3(offset, clmd->hair_grid_min); + zero_v3(a); + zero_v3(b); + + offset[axis] = shift * clmd->hair_grid_cellsize; + a[(axis + 1) % 3] = clmd->hair_grid_max[(axis + 1) % 3] - + clmd->hair_grid_min[(axis + 1) % 3]; + b[(axis + 2) % 3] = clmd->hair_grid_max[(axis + 2) % 3] - + clmd->hair_grid_min[(axis + 2) % 3]; + + BKE_sim_debug_data_clear_category(clmd->debug_data, "grid velocity"); + for (j = 0; j < size; j++) { + for (i = 0; i < size; i++) { + float x[3], v[3], gvel[3], gvel_smooth[3], gdensity; + + madd_v3_v3v3fl(x, offset, a, (float)i / (float)(size - 1)); + madd_v3_v3fl(x, b, (float)j / (float)(size - 1)); + zero_v3(v); + + SIM_hair_volume_grid_interpolate(grid, x, &gdensity, gvel, gvel_smooth, NULL, NULL); + + // BKE_sim_debug_data_add_circle( + // clmd->debug_data, x, gdensity, 0.7, 0.3, 1, + // "grid density", i, j, 3111); + if (!is_zero_v3(gvel) || !is_zero_v3(gvel_smooth)) { + float dvel[3]; + sub_v3_v3v3(dvel, gvel_smooth, gvel); + // BKE_sim_debug_data_add_vector( + // clmd->debug_data, x, gvel, 0.4, 0, 1, + // "grid velocity", i, j, 3112); + // BKE_sim_debug_data_add_vector( + // clmd->debug_data, x, gvel_smooth, 0.6, 1, 1, + // "grid velocity", i, j, 3113); + BKE_sim_debug_data_add_vector( + clmd->debug_data, x, dvel, 0.4, 1, 0.7, "grid velocity", i, j, 3114); +# if 0 + if (gdensity > 0.0f) { + float col0[3] = {0.0, 0.0, 0.0}; + float col1[3] = {0.0, 1.0, 0.0}; + float col[3]; + + interp_v3_v3v3(col, col0, col1, + CLAMPIS(gdensity * clmd->sim_parms->density_strength, 0.0, 1.0)); + // BKE_sim_debug_data_add_circle( + // clmd->debug_data, x, gdensity * clmd->sim_parms->density_strength, 0, 1, 0.4, + // "grid velocity", i, j, 3115); + // BKE_sim_debug_data_add_dot( + // clmd->debug_data, x, col[0], col[1], col[2], + // "grid velocity", i, j, 3115); + BKE_sim_debug_data_add_circle( + clmd->debug_data, x, 0.01f, col[0], col[1], col[2], "grid velocity", i, j, 3115); + } +# endif + } + } + } + } +#endif + + SIM_hair_volume_free_vertex_grid(grid); + } +} + +#if 0 +static void cloth_calc_volume_force(ClothModifierData *clmd) +{ + ClothSimSettings *parms = clmd->sim_parms; + Cloth *cloth = clmd->clothObject; + Implicit_Data *data = cloth->implicit; + int mvert_num = cloth->mvert_num; + ClothVertex *vert; + + /* 2.0f is an experimental value that seems to give good results */ + float smoothfac = 2.0f * parms->velocity_smooth; + float collfac = 2.0f * parms->collider_friction; + float pressfac = parms->pressure; + float minpress = parms->pressure_threshold; + float gmin[3], gmax[3]; + int i; + + hair_get_boundbox(clmd, gmin, gmax); + + /* gather velocities & density */ + if (smoothfac > 0.0f || pressfac > 0.0f) { + HairVertexGrid *vertex_grid = SIM_hair_volume_create_vertex_grid( + clmd->sim_parms->voxel_res, gmin, gmax); + + vert = cloth->verts; + for (i = 0; i < mvert_num; i++, vert++) { + float x[3], v[3]; + + if (vert->solver_index < 0) { + copy_v3_v3(x, vert->x); + copy_v3_v3(v, vert->v); + } + else { + SIM_mass_spring_get_motion_state(data, vert->solver_index, x, v); + } + SIM_hair_volume_add_vertex(vertex_grid, x, v); + } + SIM_hair_volume_normalize_vertex_grid(vertex_grid); + + vert = cloth->verts; + for (i = 0; i < mvert_num; i++, vert++) { + float x[3], v[3], f[3], dfdx[3][3], dfdv[3][3]; + + if (vert->solver_index < 0) { + continue; + } + + /* calculate volumetric forces */ + SIM_mass_spring_get_motion_state(data, vert->solver_index, x, v); + SIM_hair_volume_vertex_grid_forces( + vertex_grid, x, v, smoothfac, pressfac, minpress, f, dfdx, dfdv); + /* apply on hair data */ + SIM_mass_spring_force_extern(data, vert->solver_index, f, dfdx, dfdv); + } + + SIM_hair_volume_free_vertex_grid(vertex_grid); + } +} +#endif + +static void cloth_calc_average_acceleration(ClothModifierData *clmd, float dt) +{ + Cloth *cloth = clmd->clothObject; + Implicit_Data *data = cloth->implicit; + int i, mvert_num = cloth->mvert_num; + float total[3] = {0.0f, 0.0f, 0.0f}; + + for (i = 0; i < mvert_num; i++) { + float v[3], nv[3]; + + SIM_mass_spring_get_velocity(data, i, v); + SIM_mass_spring_get_new_velocity(data, i, nv); + + sub_v3_v3(nv, v); + add_v3_v3(total, nv); + } + + mul_v3_fl(total, 1.0f / dt / mvert_num); + + /* Smooth the data using a running average to prevent instability. + * This is effectively an abstraction of the wave propagation speed in fluid. */ + interp_v3_v3v3(cloth->average_acceleration, total, cloth->average_acceleration, powf(0.25f, dt)); +} + +static void cloth_solve_collisions( + Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt) +{ + Cloth *cloth = clmd->clothObject; + Implicit_Data *id = cloth->implicit; + ClothVertex *verts = cloth->verts; + int mvert_num = cloth->mvert_num; + const float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale); + int i; + + if (!(clmd->coll_parms->flags & + (CLOTH_COLLSETTINGS_FLAG_ENABLED | CLOTH_COLLSETTINGS_FLAG_SELF))) { + return; + } + + if (!clmd->clothObject->bvhtree) { + return; + } + + SIM_mass_spring_solve_positions(id, dt); + + /* Update verts to current positions. */ + for (i = 0; i < mvert_num; i++) { + SIM_mass_spring_get_new_position(id, i, verts[i].tx); + + sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold); + zero_v3(verts[i].dcvel); + } + + if (cloth_bvh_collision(depsgraph, + ob, + clmd, + step / clmd->sim_parms->timescale, + dt / clmd->sim_parms->timescale)) { + for (i = 0; i < mvert_num; i++) { + if ((clmd->sim_parms->vgroup_mass > 0) && (verts[i].flags & CLOTH_VERT_FLAG_PINNED)) { + continue; + } + + SIM_mass_spring_get_new_velocity(id, i, verts[i].tv); + madd_v3_v3fl(verts[i].tv, verts[i].dcvel, time_multiplier); + SIM_mass_spring_set_new_velocity(id, i, verts[i].tv); + } + } +} + +static void cloth_clear_result(ClothModifierData *clmd) +{ + ClothSolverResult *sres = clmd->solver_result; + + sres->status = 0; + sres->max_error = sres->min_error = sres->avg_error = 0.0f; + sres->max_iterations = sres->min_iterations = 0; + sres->avg_iterations = 0.0f; +} + +static void cloth_record_result(ClothModifierData *clmd, ImplicitSolverResult *result, float dt) +{ + ClothSolverResult *sres = clmd->solver_result; + + if (sres->status) { /* already initialized ? */ + /* error only makes sense for successful iterations */ + if (result->status == SIM_SOLVER_SUCCESS) { + sres->min_error = min_ff(sres->min_error, result->error); + sres->max_error = max_ff(sres->max_error, result->error); + sres->avg_error += result->error * dt; + } + + sres->min_iterations = min_ii(sres->min_iterations, result->iterations); + sres->max_iterations = max_ii(sres->max_iterations, result->iterations); + sres->avg_iterations += (float)result->iterations * dt; + } + else { + /* error only makes sense for successful iterations */ + if (result->status == SIM_SOLVER_SUCCESS) { + sres->min_error = sres->max_error = result->error; + sres->avg_error += result->error * dt; + } + + sres->min_iterations = sres->max_iterations = result->iterations; + sres->avg_iterations += (float)result->iterations * dt; + } + + sres->status |= result->status; +} + +int SIM_cloth_solve( + Depsgraph *depsgraph, Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors) +{ + /* Hair currently is a cloth sim in disguise ... + * Collision detection and volumetrics work differently then. + * Bad design, TODO + */ + Scene *scene = DEG_get_evaluated_scene(depsgraph); + const bool is_hair = (clmd->hairdata != NULL); + + unsigned int i = 0; + float step = 0.0f, tf = clmd->sim_parms->timescale; + Cloth *cloth = clmd->clothObject; + ClothVertex *verts = cloth->verts /*, *cv*/; + unsigned int mvert_num = cloth->mvert_num; + float dt = clmd->sim_parms->dt * clmd->sim_parms->timescale; + Implicit_Data *id = cloth->implicit; + + /* Hydrostatic pressure gradient of the fluid inside the object is affected by acceleration. */ + bool use_acceleration = (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE) && + (clmd->sim_parms->fluid_density > 0); + + BKE_sim_debug_data_clear_category("collision"); + + if (!clmd->solver_result) { + clmd->solver_result = (ClothSolverResult *)MEM_callocN(sizeof(ClothSolverResult), + "cloth solver result"); + } + cloth_clear_result(clmd); + + if (clmd->sim_parms->vgroup_mass > 0) { /* Do goal stuff. */ + for (i = 0; i < mvert_num; i++) { + // update velocities with constrained velocities from pinned verts + if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) { + float v[3]; + sub_v3_v3v3(v, verts[i].xconst, verts[i].xold); + // mul_v3_fl(v, clmd->sim_parms->stepsPerFrame); + /* divide by time_scale to prevent constrained velocities from being multiplied */ + mul_v3_fl(v, 1.0f / clmd->sim_parms->time_scale); + SIM_mass_spring_set_velocity(id, i, v); + } + } + } + + if (!use_acceleration) { + zero_v3(cloth->average_acceleration); + } + + while (step < tf) { + ImplicitSolverResult result; + + /* setup vertex constraints for pinned vertices */ + cloth_setup_constraints(clmd); + + /* initialize forces to zero */ + SIM_mass_spring_clear_forces(id); + + // calculate forces + cloth_calc_force(scene, clmd, frame, effectors, step); + + // calculate new velocity and position + SIM_mass_spring_solve_velocities(id, dt, &result); + cloth_record_result(clmd, &result, dt); + + /* Calculate collision impulses. */ + cloth_solve_collisions(depsgraph, ob, clmd, step, dt); + + if (is_hair) { + cloth_continuum_step(clmd, dt); + } + + if (use_acceleration) { + cloth_calc_average_acceleration(clmd, dt); + } + + SIM_mass_spring_solve_positions(id, dt); + SIM_mass_spring_apply_result(id); + + /* move pinned verts to correct position */ + for (i = 0; i < mvert_num; i++) { + if (clmd->sim_parms->vgroup_mass > 0) { + if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) { + float x[3]; + /* divide by time_scale to prevent pinned vertices' + * delta locations from being multiplied */ + interp_v3_v3v3( + x, verts[i].xold, verts[i].xconst, (step + dt) / clmd->sim_parms->time_scale); + SIM_mass_spring_set_position(id, i, x); + } + } + + SIM_mass_spring_get_motion_state(id, i, verts[i].txold, NULL); + } + + step += dt; + } + + /* copy results back to cloth data */ + for (i = 0; i < mvert_num; i++) { + SIM_mass_spring_get_motion_state(id, i, verts[i].x, verts[i].v); + copy_v3_v3(verts[i].txold, verts[i].x); + } + + return 1; +} diff --git a/source/blender/simulation/intern/hair_volume.cpp b/source/blender/simulation/intern/hair_volume.cpp index 1764d0a910c..c80ae69ce73 100644 --- a/source/blender/simulation/intern/hair_volume.cpp +++ b/source/blender/simulation/intern/hair_volume.cpp @@ -205,7 +205,7 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, } } -void BPH_hair_volume_vertex_grid_forces(HairGrid *grid, +void SIM_hair_volume_vertex_grid_forces(HairGrid *grid, const float x[3], const float v[3], float smoothfac, @@ -244,7 +244,7 @@ void BPH_hair_volume_vertex_grid_forces(HairGrid *grid, mul_m3_fl(dfdv, smoothfac); } -void BPH_hair_volume_grid_interpolate(HairGrid *grid, +void SIM_hair_volume_grid_interpolate(HairGrid *grid, const float x[3], float *density, float velocity[3], @@ -264,7 +264,7 @@ void BPH_hair_volume_grid_interpolate(HairGrid *grid, velocity_gradient); } -void BPH_hair_volume_grid_velocity( +void SIM_hair_volume_grid_velocity( HairGrid *grid, const float x[3], const float v[3], float fluid_factor, float r_v[3]) { float gdensity, gvelocity[3], gvel_smooth[3], ggrad[3], gvelgrad[3][3]; @@ -291,7 +291,7 @@ void BPH_hair_volume_grid_velocity( interp_v3_v3v3(r_v, v_pic, v_flip, fluid_factor); } -void BPH_hair_volume_grid_clear(HairGrid *grid) +void SIM_hair_volume_grid_clear(HairGrid *grid) { const int size = hair_grid_size(grid->res); int i; @@ -362,7 +362,7 @@ BLI_INLINE void grid_to_world(HairGrid *grid, float vecw[3], const float vec[3]) add_v3_v3(vecw, grid->gmin); } -void BPH_hair_volume_add_vertex(HairGrid *grid, const float x[3], const float v[3]) +void SIM_hair_volume_add_vertex(HairGrid *grid, const float x[3], const float v[3]) { const int res[3] = {grid->res[0], grid->res[1], grid->res[2]}; float weights[8]; @@ -503,7 +503,7 @@ BLI_INLINE void hair_volume_add_segment_2D(HairGrid *grid, * The radius of influence around a segment is assumed to be at most 2*cellsize, * i.e. only cells containing the segment and their direct neighbors are examined. */ -void BPH_hair_volume_add_segment(HairGrid *grid, +void SIM_hair_volume_add_segment(HairGrid *grid, const float x1[3], const float v1[3], const float x2[3], @@ -633,7 +633,7 @@ BLI_INLINE void hair_volume_eval_grid_vertex_sample(HairGridVert *vert, /* XXX simplified test implementation using a series of discrete sample along the segment, * instead of finding the closest point for all affected grid vertices. */ -void BPH_hair_volume_add_segment(HairGrid *grid, +void SIM_hair_volume_add_segment(HairGrid *grid, const float UNUSED(x1[3]), const float UNUSED(v1[3]), const float x2[3], @@ -684,7 +684,7 @@ void BPH_hair_volume_add_segment(HairGrid *grid, } #endif -void BPH_hair_volume_normalize_vertex_grid(HairGrid *grid) +void SIM_hair_volume_normalize_vertex_grid(HairGrid *grid) { int i, size = hair_grid_size(grid->res); /* divide velocity with density */ @@ -715,7 +715,7 @@ BLI_INLINE float hair_volume_density_divergence(float density, } } -bool BPH_hair_volume_solve_divergence(HairGrid *grid, +bool SIM_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target_density, float target_strength) @@ -1078,7 +1078,7 @@ BLI_INLINE void hair_volume_filter_box_convolute( } } -void BPH_hair_volume_vertex_grid_filter_box(HairVertexGrid *grid, int kernel_size) +void SIM_hair_volume_vertex_grid_filter_box(HairVertexGrid *grid, int kernel_size) { int size = hair_grid_size(grid->res); int kernel_sizev[3] = {kernel_size, kernel_size, kernel_size}; @@ -1113,7 +1113,7 @@ void BPH_hair_volume_vertex_grid_filter_box(HairVertexGrid *grid, int kernel_siz } #endif -HairGrid *BPH_hair_volume_create_vertex_grid(float cellsize, +HairGrid *SIM_hair_volume_create_vertex_grid(float cellsize, const float gmin[3], const float gmax[3]) { @@ -1170,7 +1170,7 @@ HairGrid *BPH_hair_volume_create_vertex_grid(float cellsize, return grid; } -void BPH_hair_volume_free_vertex_grid(HairGrid *grid) +void SIM_hair_volume_free_vertex_grid(HairGrid *grid) { if (grid) { if (grid->verts) { @@ -1180,7 +1180,7 @@ void BPH_hair_volume_free_vertex_grid(HairGrid *grid) } } -void BPH_hair_volume_grid_geometry( +void SIM_hair_volume_grid_geometry( HairGrid *grid, float *cellsize, int res[3], float gmin[3], float gmax[3]) { if (cellsize) { diff --git a/source/blender/simulation/intern/implicit.h b/source/blender/simulation/intern/implicit.h index 8bc09755180..17dfb8b88b9 100644 --- a/source/blender/simulation/intern/implicit.h +++ b/source/blender/simulation/intern/implicit.h @@ -65,87 +65,87 @@ BLI_INLINE void implicit_print_matrix_elem(float v) printf("%-8.3f", v); } -void BPH_mass_spring_set_vertex_mass(struct Implicit_Data *data, int index, float mass); -void BPH_mass_spring_set_rest_transform(struct Implicit_Data *data, int index, float rot[3][3]); +void SIM_mass_spring_set_vertex_mass(struct Implicit_Data *data, int index, float mass); +void SIM_mass_spring_set_rest_transform(struct Implicit_Data *data, int index, float rot[3][3]); -void BPH_mass_spring_set_motion_state(struct Implicit_Data *data, +void SIM_mass_spring_set_motion_state(struct Implicit_Data *data, int index, const float x[3], const float v[3]); -void BPH_mass_spring_set_position(struct Implicit_Data *data, int index, const float x[3]); -void BPH_mass_spring_set_velocity(struct Implicit_Data *data, int index, const float v[3]); -void BPH_mass_spring_get_motion_state(struct Implicit_Data *data, +void SIM_mass_spring_set_position(struct Implicit_Data *data, int index, const float x[3]); +void SIM_mass_spring_set_velocity(struct Implicit_Data *data, int index, const float v[3]); +void SIM_mass_spring_get_motion_state(struct Implicit_Data *data, int index, float x[3], float v[3]); -void BPH_mass_spring_get_position(struct Implicit_Data *data, int index, float x[3]); -void BPH_mass_spring_get_velocity(struct Implicit_Data *data, int index, float v[3]); +void SIM_mass_spring_get_position(struct Implicit_Data *data, int index, float x[3]); +void SIM_mass_spring_get_velocity(struct Implicit_Data *data, int index, float v[3]); /* access to modified motion state during solver step */ -void BPH_mass_spring_get_new_position(struct Implicit_Data *data, int index, float x[3]); -void BPH_mass_spring_set_new_position(struct Implicit_Data *data, int index, const float x[3]); -void BPH_mass_spring_get_new_velocity(struct Implicit_Data *data, int index, float v[3]); -void BPH_mass_spring_set_new_velocity(struct Implicit_Data *data, int index, const float v[3]); +void SIM_mass_spring_get_new_position(struct Implicit_Data *data, int index, float x[3]); +void SIM_mass_spring_set_new_position(struct Implicit_Data *data, int index, const float x[3]); +void SIM_mass_spring_get_new_velocity(struct Implicit_Data *data, int index, float v[3]); +void SIM_mass_spring_set_new_velocity(struct Implicit_Data *data, int index, const float v[3]); -void BPH_mass_spring_clear_constraints(struct Implicit_Data *data); -void BPH_mass_spring_add_constraint_ndof0(struct Implicit_Data *data, +void SIM_mass_spring_clear_constraints(struct Implicit_Data *data); +void SIM_mass_spring_add_constraint_ndof0(struct Implicit_Data *data, int index, const float dV[3]); -void BPH_mass_spring_add_constraint_ndof1(struct Implicit_Data *data, +void SIM_mass_spring_add_constraint_ndof1(struct Implicit_Data *data, int index, const float c1[3], const float c2[3], const float dV[3]); -void BPH_mass_spring_add_constraint_ndof2(struct Implicit_Data *data, +void SIM_mass_spring_add_constraint_ndof2(struct Implicit_Data *data, int index, const float c1[3], const float dV[3]); -bool BPH_mass_spring_solve_velocities(struct Implicit_Data *data, +bool SIM_mass_spring_solve_velocities(struct Implicit_Data *data, float dt, struct ImplicitSolverResult *result); -bool BPH_mass_spring_solve_positions(struct Implicit_Data *data, float dt); -void BPH_mass_spring_apply_result(struct Implicit_Data *data); +bool SIM_mass_spring_solve_positions(struct Implicit_Data *data, float dt); +void SIM_mass_spring_apply_result(struct Implicit_Data *data); /* Clear the force vector at the beginning of the time step */ -void BPH_mass_spring_clear_forces(struct Implicit_Data *data); +void SIM_mass_spring_clear_forces(struct Implicit_Data *data); /* Fictitious forces introduced by moving coordinate systems */ -void BPH_mass_spring_force_reference_frame(struct Implicit_Data *data, +void SIM_mass_spring_force_reference_frame(struct Implicit_Data *data, int index, const float acceleration[3], const float omega[3], const float domega_dt[3], float mass); /* Simple uniform gravity force */ -void BPH_mass_spring_force_gravity(struct Implicit_Data *data, +void SIM_mass_spring_force_gravity(struct Implicit_Data *data, int index, float mass, const float g[3]); /* Global drag force (velocity damping) */ -void BPH_mass_spring_force_drag(struct Implicit_Data *data, float drag); +void SIM_mass_spring_force_drag(struct Implicit_Data *data, float drag); /* Custom external force */ -void BPH_mass_spring_force_extern( +void SIM_mass_spring_force_extern( struct Implicit_Data *data, int i, const float f[3], float dfdx[3][3], float dfdv[3][3]); /* Wind force, acting on a face (only generates pressure from the normal component) */ -void BPH_mass_spring_force_face_wind( +void SIM_mass_spring_force_face_wind( struct Implicit_Data *data, int v1, int v2, int v3, const float (*winvec)[3]); /* Arbitrary per-unit-area vector force field acting on a face. */ -void BPH_mass_spring_force_face_extern( +void SIM_mass_spring_force_face_extern( struct Implicit_Data *data, int v1, int v2, int v3, const float (*forcevec)[3]); /* Wind force, acting on an edge */ -void BPH_mass_spring_force_edge_wind(struct Implicit_Data *data, +void SIM_mass_spring_force_edge_wind(struct Implicit_Data *data, int v1, int v2, float radius1, float radius2, const float (*winvec)[3]); /* Wind force, acting on a vertex */ -void BPH_mass_spring_force_vertex_wind(struct Implicit_Data *data, +void SIM_mass_spring_force_vertex_wind(struct Implicit_Data *data, int v, float radius, const float (*winvec)[3]); /* Linear spring force between two points */ -bool BPH_mass_spring_force_spring_linear(struct Implicit_Data *data, +bool SIM_mass_spring_force_spring_linear(struct Implicit_Data *data, int i, int j, float restlen, @@ -157,7 +157,7 @@ bool BPH_mass_spring_force_spring_linear(struct Implicit_Data *data, bool new_compress, float clamp_force); /* Angular spring force between two polygons */ -bool BPH_mass_spring_force_spring_angular(struct Implicit_Data *data, +bool SIM_mass_spring_force_spring_angular(struct Implicit_Data *data, int i, int j, int *i_a, @@ -168,10 +168,10 @@ bool BPH_mass_spring_force_spring_angular(struct Implicit_Data *data, float stiffness, float damping); /* Bending force, forming a triangle at the base of two structural springs */ -bool BPH_mass_spring_force_spring_bending( +bool SIM_mass_spring_force_spring_bending( struct Implicit_Data *data, int i, int j, float restlen, float kb, float cb); /* Angular bending force based on local target vectors */ -bool BPH_mass_spring_force_spring_bending_hair(struct Implicit_Data *data, +bool SIM_mass_spring_force_spring_bending_hair(struct Implicit_Data *data, int i, int j, int k, @@ -179,17 +179,17 @@ bool BPH_mass_spring_force_spring_bending_hair(struct Implicit_Data *data, float stiffness, float damping); /* Global goal spring */ -bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data, +bool SIM_mass_spring_force_spring_goal(struct Implicit_Data *data, int i, const float goal_x[3], const float goal_v[3], float stiffness, float damping); -float BPH_tri_tetra_volume_signed_6x(struct Implicit_Data *data, int v1, int v2, int v3); -float BPH_tri_area(struct Implicit_Data *data, int v1, int v2, int v3); +float SIM_tri_tetra_volume_signed_6x(struct Implicit_Data *data, int v1, int v2, int v3); +float SIM_tri_area(struct Implicit_Data *data, int v1, int v2, int v3); -void BPH_mass_spring_force_pressure(struct Implicit_Data *data, +void SIM_mass_spring_force_pressure(struct Implicit_Data *data, int v1, int v2, int v3, @@ -203,16 +203,16 @@ struct HairGrid; #define MAX_HAIR_GRID_RES 256 -struct HairGrid *BPH_hair_volume_create_vertex_grid(float cellsize, +struct HairGrid *SIM_hair_volume_create_vertex_grid(float cellsize, const float gmin[3], const float gmax[3]); -void BPH_hair_volume_free_vertex_grid(struct HairGrid *grid); -void BPH_hair_volume_grid_geometry( +void SIM_hair_volume_free_vertex_grid(struct HairGrid *grid); +void SIM_hair_volume_grid_geometry( struct HairGrid *grid, float *cellsize, int res[3], float gmin[3], float gmax[3]); -void BPH_hair_volume_grid_clear(struct HairGrid *grid); -void BPH_hair_volume_add_vertex(struct HairGrid *grid, const float x[3], const float v[3]); -void BPH_hair_volume_add_segment(struct HairGrid *grid, +void SIM_hair_volume_grid_clear(struct HairGrid *grid); +void SIM_hair_volume_add_vertex(struct HairGrid *grid, const float x[3], const float v[3]); +void SIM_hair_volume_add_segment(struct HairGrid *grid, const float x1[3], const float v1[3], const float x2[3], @@ -225,17 +225,17 @@ void BPH_hair_volume_add_segment(struct HairGrid *grid, const float dir2[3], const float dir3[3]); -void BPH_hair_volume_normalize_vertex_grid(struct HairGrid *grid); +void SIM_hair_volume_normalize_vertex_grid(struct HairGrid *grid); -bool BPH_hair_volume_solve_divergence(struct HairGrid *grid, +bool SIM_hair_volume_solve_divergence(struct HairGrid *grid, float dt, float target_density, float target_strength); #if 0 /* XXX weighting is incorrect, disabled for now */ -void BPH_hair_volume_vertex_grid_filter_box(struct HairVertexGrid *grid, int kernel_size); +void SIM_hair_volume_vertex_grid_filter_box(struct HairVertexGrid *grid, int kernel_size); #endif -void BPH_hair_volume_grid_interpolate(struct HairGrid *grid, +void SIM_hair_volume_grid_interpolate(struct HairGrid *grid, const float x[3], float *density, float velocity[3], @@ -247,7 +247,7 @@ void BPH_hair_volume_grid_interpolate(struct HairGrid *grid, * fluid_factor controls blending between PIC (Particle-in-Cell) * and FLIP (Fluid-Implicit-Particle) methods (0 = only PIC, 1 = only FLIP) */ -void BPH_hair_volume_grid_velocity( +void SIM_hair_volume_grid_velocity( struct HairGrid *grid, const float x[3], const float v[3], float fluid_factor, float r_v[3]); /* XXX Warning: expressing grid effects on velocity as a force is not very stable, * due to discontinuities in interpolated values! @@ -255,7 +255,7 @@ void BPH_hair_volume_grid_velocity( * "Detail Preserving Continuum Simulation of Straight Hair" * (McAdams, Selle 2009) */ -void BPH_hair_volume_vertex_grid_forces(struct HairGrid *grid, +void SIM_hair_volume_vertex_grid_forces(struct HairGrid *grid, const float x[3], const float v[3], float smoothfac, diff --git a/source/blender/simulation/intern/implicit_blender.c b/source/blender/simulation/intern/implicit_blender.c index 54d38f3c10b..856572aa3f5 100644 --- a/source/blender/simulation/intern/implicit_blender.c +++ b/source/blender/simulation/intern/implicit_blender.c @@ -40,7 +40,7 @@ # include "BKE_collision.h" # include "BKE_effect.h" -# include "BPH_mass_spring.h" +# include "SIM_mass_spring.h" # ifdef __GNUC__ # pragma GCC diagnostic ignored "-Wtype-limits" @@ -679,7 +679,7 @@ typedef struct Implicit_Data { fmatrix3x3 *P, *Pinv; /* pre-conditioning matrix */ } Implicit_Data; -Implicit_Data *BPH_mass_spring_solver_create(int numverts, int numsprings) +Implicit_Data *SIM_mass_spring_solver_create(int numverts, int numsprings) { Implicit_Data *id = (Implicit_Data *)MEM_callocN(sizeof(Implicit_Data), "implicit vecmat"); @@ -707,7 +707,7 @@ Implicit_Data *BPH_mass_spring_solver_create(int numverts, int numsprings) return id; } -void BPH_mass_spring_solver_free(Implicit_Data *id) +void SIM_mass_spring_solver_free(Implicit_Data *id) { del_bfmatrix(id->tfm); del_bfmatrix(id->A); @@ -924,8 +924,8 @@ static int cg_filtered(lfVector *ldV, del_lfvector(s); // printf("W/O conjgrad_loopcount: %d\n", conjgrad_loopcount); - result->status = conjgrad_loopcount < conjgrad_looplimit ? BPH_SOLVER_SUCCESS : - BPH_SOLVER_NO_CONVERGENCE; + result->status = conjgrad_loopcount < conjgrad_looplimit ? SIM_SOLVER_SUCCESS : + SIM_SOLVER_NO_CONVERGENCE; result->iterations = conjgrad_loopcount; result->error = bnorm2 > 0.0f ? sqrtf(delta_new / bnorm2) : 0.0f; @@ -1139,7 +1139,7 @@ static int cg_filtered_pre(lfVector *dv, } # endif -bool BPH_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSolverResult *result) +bool SIM_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSolverResult *result) { unsigned int numverts = data->dFdV[0].vcount; @@ -1173,10 +1173,10 @@ bool BPH_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSol del_lfvector(dFdXmV); - return result->status == BPH_SOLVER_SUCCESS; + return result->status == SIM_SOLVER_SUCCESS; } -bool BPH_mass_spring_solve_positions(Implicit_Data *data, float dt) +bool SIM_mass_spring_solve_positions(Implicit_Data *data, float dt) { int numverts = data->M[0].vcount; @@ -1186,20 +1186,20 @@ bool BPH_mass_spring_solve_positions(Implicit_Data *data, float dt) return true; } -void BPH_mass_spring_apply_result(Implicit_Data *data) +void SIM_mass_spring_apply_result(Implicit_Data *data) { int numverts = data->M[0].vcount; cp_lfvector(data->X, data->Xnew, numverts); cp_lfvector(data->V, data->Vnew, numverts); } -void BPH_mass_spring_set_vertex_mass(Implicit_Data *data, int index, float mass) +void SIM_mass_spring_set_vertex_mass(Implicit_Data *data, int index, float mass) { unit_m3(data->M[index].m); mul_m3_fl(data->M[index].m, mass); } -void BPH_mass_spring_set_rest_transform(Implicit_Data *data, int index, float tfm[3][3]) +void SIM_mass_spring_set_rest_transform(Implicit_Data *data, int index, float tfm[3][3]) { # ifdef CLOTH_ROOT_FRAME copy_m3_m3(data->tfm[index].m, tfm); @@ -1209,7 +1209,7 @@ void BPH_mass_spring_set_rest_transform(Implicit_Data *data, int index, float tf # endif } -void BPH_mass_spring_set_motion_state(Implicit_Data *data, +void SIM_mass_spring_set_motion_state(Implicit_Data *data, int index, const float x[3], const float v[3]) @@ -1218,17 +1218,17 @@ void BPH_mass_spring_set_motion_state(Implicit_Data *data, world_to_root_v3(data, index, data->V[index], v); } -void BPH_mass_spring_set_position(Implicit_Data *data, int index, const float x[3]) +void SIM_mass_spring_set_position(Implicit_Data *data, int index, const float x[3]) { world_to_root_v3(data, index, data->X[index], x); } -void BPH_mass_spring_set_velocity(Implicit_Data *data, int index, const float v[3]) +void SIM_mass_spring_set_velocity(Implicit_Data *data, int index, const float v[3]) { world_to_root_v3(data, index, data->V[index], v); } -void BPH_mass_spring_get_motion_state(struct Implicit_Data *data, +void SIM_mass_spring_get_motion_state(struct Implicit_Data *data, int index, float x[3], float v[3]) @@ -1241,39 +1241,39 @@ void BPH_mass_spring_get_motion_state(struct Implicit_Data *data, } } -void BPH_mass_spring_get_position(struct Implicit_Data *data, int index, float x[3]) +void SIM_mass_spring_get_position(struct Implicit_Data *data, int index, float x[3]) { root_to_world_v3(data, index, x, data->X[index]); } -void BPH_mass_spring_get_velocity(struct Implicit_Data *data, int index, float v[3]) +void SIM_mass_spring_get_velocity(struct Implicit_Data *data, int index, float v[3]) { root_to_world_v3(data, index, v, data->V[index]); } -void BPH_mass_spring_get_new_position(struct Implicit_Data *data, int index, float x[3]) +void SIM_mass_spring_get_new_position(struct Implicit_Data *data, int index, float x[3]) { root_to_world_v3(data, index, x, data->Xnew[index]); } -void BPH_mass_spring_set_new_position(struct Implicit_Data *data, int index, const float x[3]) +void SIM_mass_spring_set_new_position(struct Implicit_Data *data, int index, const float x[3]) { world_to_root_v3(data, index, data->Xnew[index], x); } -void BPH_mass_spring_get_new_velocity(struct Implicit_Data *data, int index, float v[3]) +void SIM_mass_spring_get_new_velocity(struct Implicit_Data *data, int index, float v[3]) { root_to_world_v3(data, index, v, data->Vnew[index]); } -void BPH_mass_spring_set_new_velocity(struct Implicit_Data *data, int index, const float v[3]) +void SIM_mass_spring_set_new_velocity(struct Implicit_Data *data, int index, const float v[3]) { world_to_root_v3(data, index, data->Vnew[index], v); } /* -------------------------------- */ -static int BPH_mass_spring_add_block(Implicit_Data *data, int v1, int v2) +static int SIM_mass_spring_add_block(Implicit_Data *data, int v1, int v2) { int s = data->M[0].vcount + data->num_blocks; /* index from array start */ BLI_assert(s < data->M[0].vcount + data->M[0].scount); @@ -1291,7 +1291,7 @@ static int BPH_mass_spring_add_block(Implicit_Data *data, int v1, int v2) return s; } -void BPH_mass_spring_clear_constraints(Implicit_Data *data) +void SIM_mass_spring_clear_constraints(Implicit_Data *data) { int i, numverts = data->S[0].vcount; for (i = 0; i < numverts; i++) { @@ -1300,14 +1300,14 @@ void BPH_mass_spring_clear_constraints(Implicit_Data *data) } } -void BPH_mass_spring_add_constraint_ndof0(Implicit_Data *data, int index, const float dV[3]) +void SIM_mass_spring_add_constraint_ndof0(Implicit_Data *data, int index, const float dV[3]) { zero_m3(data->S[index].m); world_to_root_v3(data, index, data->z[index], dV); } -void BPH_mass_spring_add_constraint_ndof1( +void SIM_mass_spring_add_constraint_ndof1( Implicit_Data *data, int index, const float c1[3], const float c2[3], const float dV[3]) { float m[3][3], p[3], q[3], u[3], cmat[3][3]; @@ -1328,7 +1328,7 @@ void BPH_mass_spring_add_constraint_ndof1( add_v3_v3(data->z[index], u); } -void BPH_mass_spring_add_constraint_ndof2(Implicit_Data *data, +void SIM_mass_spring_add_constraint_ndof2(Implicit_Data *data, int index, const float c1[3], const float dV[3]) @@ -1346,7 +1346,7 @@ void BPH_mass_spring_add_constraint_ndof2(Implicit_Data *data, add_v3_v3(data->z[index], u); } -void BPH_mass_spring_clear_forces(Implicit_Data *data) +void SIM_mass_spring_clear_forces(Implicit_Data *data) { int numverts = data->M[0].vcount; zero_lfvector(data->F, numverts); @@ -1356,7 +1356,7 @@ void BPH_mass_spring_clear_forces(Implicit_Data *data) data->num_blocks = 0; } -void BPH_mass_spring_force_reference_frame(Implicit_Data *data, +void SIM_mass_spring_force_reference_frame(Implicit_Data *data, int index, const float acceleration[3], const float omega[3], @@ -1411,7 +1411,7 @@ void BPH_mass_spring_force_reference_frame(Implicit_Data *data, # endif } -void BPH_mass_spring_force_gravity(Implicit_Data *data, int index, float mass, const float g[3]) +void SIM_mass_spring_force_gravity(Implicit_Data *data, int index, float mass, const float g[3]) { /* force = mass * acceleration (in this case: gravity) */ float f[3]; @@ -1421,7 +1421,7 @@ void BPH_mass_spring_force_gravity(Implicit_Data *data, int index, float mass, c add_v3_v3(data->F[index], f); } -void BPH_mass_spring_force_drag(Implicit_Data *data, float drag) +void SIM_mass_spring_force_drag(Implicit_Data *data, float drag) { int i, numverts = data->M[0].vcount; for (i = 0; i < numverts; i++) { @@ -1436,7 +1436,7 @@ void BPH_mass_spring_force_drag(Implicit_Data *data, float drag) } } -void BPH_mass_spring_force_extern( +void SIM_mass_spring_force_extern( struct Implicit_Data *data, int i, const float f[3], float dfdx[3][3], float dfdv[3][3]) { float tf[3], tdfdx[3][3], tdfdv[3][3]; @@ -1465,7 +1465,7 @@ static float calc_nor_area_tri(float nor[3], /* XXX does not support force jacobians yet, since the effector system does not provide them either */ -void BPH_mass_spring_force_face_wind( +void SIM_mass_spring_force_face_wind( Implicit_Data *data, int v1, int v2, int v3, const float (*winvec)[3]) { const float effector_scale = 0.02f; @@ -1505,7 +1505,7 @@ void BPH_mass_spring_force_face_wind( madd_v3_v3fl(data->F[v3], nor, base_force + force[2]); } -void BPH_mass_spring_force_face_extern( +void SIM_mass_spring_force_face_extern( Implicit_Data *data, int v1, int v2, int v3, const float (*forcevec)[3]) { const float effector_scale = 0.02f; @@ -1536,20 +1536,20 @@ void BPH_mass_spring_force_face_extern( } } -float BPH_tri_tetra_volume_signed_6x(Implicit_Data *data, int v1, int v2, int v3) +float SIM_tri_tetra_volume_signed_6x(Implicit_Data *data, int v1, int v2, int v3) { /* The result will be 6x the volume */ return volume_tri_tetrahedron_signed_v3_6x(data->X[v1], data->X[v2], data->X[v3]); } -float BPH_tri_area(struct Implicit_Data *data, int v1, int v2, int v3) +float SIM_tri_area(struct Implicit_Data *data, int v1, int v2, int v3) { float nor[3]; return calc_nor_area_tri(nor, data->X[v1], data->X[v2], data->X[v3]); } -void BPH_mass_spring_force_pressure(Implicit_Data *data, +void SIM_mass_spring_force_pressure(Implicit_Data *data, int v1, int v2, int v3, @@ -1617,7 +1617,7 @@ static void edge_wind_vertex(const float dir[3], mul_v3_v3fl(f, wind, density * cross_section); } -void BPH_mass_spring_force_edge_wind( +void SIM_mass_spring_force_edge_wind( Implicit_Data *data, int v1, int v2, float radius1, float radius2, const float (*winvec)[3]) { float win[3], dir[3], length; @@ -1635,7 +1635,7 @@ void BPH_mass_spring_force_edge_wind( add_v3_v3(data->F[v2], f); } -void BPH_mass_spring_force_vertex_wind(Implicit_Data *data, +void SIM_mass_spring_force_vertex_wind(Implicit_Data *data, int v, float UNUSED(radius), const float (*winvec)[3]) @@ -1766,7 +1766,7 @@ BLI_INLINE bool spring_length(Implicit_Data *data, BLI_INLINE void apply_spring( Implicit_Data *data, int i, int j, const float f[3], float dfdx[3][3], float dfdv[3][3]) { - int block_ij = BPH_mass_spring_add_block(data, i, j); + int block_ij = SIM_mass_spring_add_block(data, i, j); add_v3_v3(data->F[i], f); sub_v3_v3(data->F[j], f); @@ -1780,7 +1780,7 @@ BLI_INLINE void apply_spring( sub_m3_m3m3(data->dFdV[block_ij].m, data->dFdV[block_ij].m, dfdv); } -bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, +bool SIM_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, float restlen, @@ -1841,7 +1841,7 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, } /* See "Stable but Responsive Cloth" (Choi, Ko 2005) */ -bool BPH_mass_spring_force_spring_bending( +bool SIM_mass_spring_force_spring_bending( Implicit_Data *data, int i, int j, float restlen, float kb, float cb) { float extent[3], length, dir[3], vel[3]; @@ -1948,7 +1948,7 @@ BLI_INLINE void spring_angle(Implicit_Data *data, /* Angular springs roughly based on the bending model proposed by Baraff and Witkin in "Large Steps * in Cloth Simulation". */ -bool BPH_mass_spring_force_spring_angular(Implicit_Data *data, +bool SIM_mass_spring_force_spring_angular(Implicit_Data *data, int i, int j, int *i_a, @@ -2169,7 +2169,7 @@ BLI_INLINE void spring_hairbend_estimate_dfdv(Implicit_Data *data, /* Angular spring that pulls the vertex toward the local target * See "Artistic Simulation of Curly Hair" (Pixar technical memo #12-03a) */ -bool BPH_mass_spring_force_spring_bending_hair(Implicit_Data *data, +bool SIM_mass_spring_force_spring_bending_hair(Implicit_Data *data, int i, int j, int k, @@ -2184,9 +2184,9 @@ bool BPH_mass_spring_force_spring_bending_hair(Implicit_Data *data, const float vecnull[3] = {0.0f, 0.0f, 0.0f}; - int block_ij = BPH_mass_spring_add_block(data, i, j); - int block_jk = BPH_mass_spring_add_block(data, j, k); - int block_ik = BPH_mass_spring_add_block(data, i, k); + int block_ij = SIM_mass_spring_add_block(data, i, j); + int block_jk = SIM_mass_spring_add_block(data, j, k); + int block_ik = SIM_mass_spring_add_block(data, i, k); world_to_root_v3(data, j, goal, target); @@ -2318,7 +2318,7 @@ bool BPH_mass_spring_force_spring_bending_hair(Implicit_Data *data, return true; } -bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, +bool SIM_mass_spring_force_spring_goal(Implicit_Data *data, int i, const float goal_x[3], const float goal_v[3], diff --git a/source/blender/simulation/intern/implicit_eigen.cpp b/source/blender/simulation/intern/implicit_eigen.cpp index 58538c13116..15b9e30e32a 100644 --- a/source/blender/simulation/intern/implicit_eigen.cpp +++ b/source/blender/simulation/intern/implicit_eigen.cpp @@ -78,7 +78,7 @@ extern "C" { # include "BKE_effect.h" # include "BKE_global.h" -# include "BPH_mass_spring.h" +# include "SIM_mass_spring.h" } typedef float Scalar; @@ -460,20 +460,20 @@ struct Implicit_Data { lMatrixCtor iS; /* filtering matrix for constraints */ }; -Implicit_Data *BPH_mass_spring_solver_create(int numverts, int numsprings) +Implicit_Data *SIM_mass_spring_solver_create(int numverts, int numsprings) { Implicit_Data *id = new Implicit_Data(numverts); return id; } -void BPH_mass_spring_solver_free(Implicit_Data *id) +void SIM_mass_spring_solver_free(Implicit_Data *id) { if (id) { delete id; } } -int BPH_mass_spring_solver_numvert(Implicit_Data *id) +int SIM_mass_spring_solver_numvert(Implicit_Data *id) { if (id) { return id->numverts; @@ -511,7 +511,7 @@ BLI_INLINE void root_to_world_m3(Implicit_Data *data, int index, float r[3][3], /* ================================ */ -bool BPH_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSolverResult *result) +bool SIM_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSolverResult *result) { # ifdef USE_EIGEN_CORE typedef ConjugateGradient solver_t; @@ -566,16 +566,16 @@ bool BPH_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSol switch (cg.info()) { case Eigen::Success: - result->status = BPH_SOLVER_SUCCESS; + result->status = SIM_SOLVER_SUCCESS; break; case Eigen::NoConvergence: - result->status = BPH_SOLVER_NO_CONVERGENCE; + result->status = SIM_SOLVER_NO_CONVERGENCE; break; case Eigen::InvalidInput: - result->status = BPH_SOLVER_INVALID_INPUT; + result->status = SIM_SOLVER_INVALID_INPUT; break; case Eigen::NumericalIssue: - result->status = BPH_SOLVER_NUMERICAL_ISSUE; + result->status = SIM_SOLVER_NUMERICAL_ISSUE; break; } @@ -585,7 +585,7 @@ bool BPH_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSol return cg.info() == Eigen::Success; } -bool BPH_mass_spring_solve_positions(Implicit_Data *data, float dt) +bool SIM_mass_spring_solve_positions(Implicit_Data *data, float dt) { data->Xnew = data->X + data->Vnew * dt; return true; @@ -593,13 +593,13 @@ bool BPH_mass_spring_solve_positions(Implicit_Data *data, float dt) /* ================================ */ -void BPH_mass_spring_apply_result(Implicit_Data *data) +void SIM_mass_spring_apply_result(Implicit_Data *data) { data->X = data->Xnew; data->V = data->Vnew; } -void BPH_mass_spring_set_vertex_mass(Implicit_Data *data, int index, float mass) +void SIM_mass_spring_set_vertex_mass(Implicit_Data *data, int index, float mass) { float m[3][3]; copy_m3_m3(m, I); @@ -607,7 +607,7 @@ void BPH_mass_spring_set_vertex_mass(Implicit_Data *data, int index, float mass) data->iM.add(index, index, m); } -void BPH_mass_spring_set_rest_transform(Implicit_Data *data, int index, float tfm[3][3]) +void SIM_mass_spring_set_rest_transform(Implicit_Data *data, int index, float tfm[3][3]) { # ifdef CLOTH_ROOT_FRAME copy_m3_m3(data->tfm[index], tfm); @@ -617,7 +617,7 @@ void BPH_mass_spring_set_rest_transform(Implicit_Data *data, int index, float tf # endif } -void BPH_mass_spring_set_motion_state(Implicit_Data *data, +void SIM_mass_spring_set_motion_state(Implicit_Data *data, int index, const float x[3], const float v[3]) @@ -626,17 +626,17 @@ void BPH_mass_spring_set_motion_state(Implicit_Data *data, world_to_root_v3(data, index, data->V.v3(index), v); } -void BPH_mass_spring_set_position(Implicit_Data *data, int index, const float x[3]) +void SIM_mass_spring_set_position(Implicit_Data *data, int index, const float x[3]) { world_to_root_v3(data, index, data->X.v3(index), x); } -void BPH_mass_spring_set_velocity(Implicit_Data *data, int index, const float v[3]) +void SIM_mass_spring_set_velocity(Implicit_Data *data, int index, const float v[3]) { world_to_root_v3(data, index, data->V.v3(index), v); } -void BPH_mass_spring_get_motion_state(struct Implicit_Data *data, +void SIM_mass_spring_get_motion_state(struct Implicit_Data *data, int index, float x[3], float v[3]) @@ -649,22 +649,22 @@ void BPH_mass_spring_get_motion_state(struct Implicit_Data *data, } } -void BPH_mass_spring_get_position(struct Implicit_Data *data, int index, float x[3]) +void SIM_mass_spring_get_position(struct Implicit_Data *data, int index, float x[3]) { root_to_world_v3(data, index, x, data->X.v3(index)); } -void BPH_mass_spring_get_new_velocity(Implicit_Data *data, int index, float v[3]) +void SIM_mass_spring_get_new_velocity(Implicit_Data *data, int index, float v[3]) { root_to_world_v3(data, index, v, data->V.v3(index)); } -void BPH_mass_spring_set_new_velocity(Implicit_Data *data, int index, const float v[3]) +void SIM_mass_spring_set_new_velocity(Implicit_Data *data, int index, const float v[3]) { world_to_root_v3(data, index, data->V.v3(index), v); } -void BPH_mass_spring_clear_constraints(Implicit_Data *data) +void SIM_mass_spring_clear_constraints(Implicit_Data *data) { int numverts = data->numverts; for (int i = 0; i < numverts; i++) { @@ -673,14 +673,14 @@ void BPH_mass_spring_clear_constraints(Implicit_Data *data) } } -void BPH_mass_spring_add_constraint_ndof0(Implicit_Data *data, int index, const float dV[3]) +void SIM_mass_spring_add_constraint_ndof0(Implicit_Data *data, int index, const float dV[3]) { data->iS.sub(index, index, I); world_to_root_v3(data, index, data->z.v3(index), dV); } -void BPH_mass_spring_add_constraint_ndof1( +void SIM_mass_spring_add_constraint_ndof1( Implicit_Data *data, int index, const float c1[3], const float c2[3], const float dV[3]) { float m[3][3], p[3], q[3], u[3], cmat[3][3]; @@ -701,7 +701,7 @@ void BPH_mass_spring_add_constraint_ndof1( add_v3_v3(data->z.v3(index), u); } -void BPH_mass_spring_add_constraint_ndof2(Implicit_Data *data, +void SIM_mass_spring_add_constraint_ndof2(Implicit_Data *data, int index, const float c1[3], const float dV[3]) @@ -719,14 +719,14 @@ void BPH_mass_spring_add_constraint_ndof2(Implicit_Data *data, add_v3_v3(data->z.v3(index), u); } -void BPH_mass_spring_clear_forces(Implicit_Data *data) +void SIM_mass_spring_clear_forces(Implicit_Data *data) { data->F.setZero(); data->dFdX.setZero(); data->dFdV.setZero(); } -void BPH_mass_spring_force_reference_frame(Implicit_Data *data, +void SIM_mass_spring_force_reference_frame(Implicit_Data *data, int index, const float acceleration[3], const float omega[3], @@ -781,7 +781,7 @@ void BPH_mass_spring_force_reference_frame(Implicit_Data *data, # endif } -void BPH_mass_spring_force_gravity(Implicit_Data *data, int index, float mass, const float g[3]) +void SIM_mass_spring_force_gravity(Implicit_Data *data, int index, float mass, const float g[3]) { /* force = mass * acceleration (in this case: gravity) */ float f[3]; @@ -791,7 +791,7 @@ void BPH_mass_spring_force_gravity(Implicit_Data *data, int index, float mass, c add_v3_v3(data->F.v3(index), f); } -void BPH_mass_spring_force_drag(Implicit_Data *data, float drag) +void SIM_mass_spring_force_drag(Implicit_Data *data, float drag) { int numverts = data->numverts; for (int i = 0; i < numverts; i++) { @@ -806,7 +806,7 @@ void BPH_mass_spring_force_drag(Implicit_Data *data, float drag) } } -void BPH_mass_spring_force_extern( +void SIM_mass_spring_force_extern( struct Implicit_Data *data, int i, const float f[3], float dfdx[3][3], float dfdv[3][3]) { float tf[3], tdfdx[3][3], tdfdv[3][3]; @@ -835,7 +835,7 @@ static float calc_nor_area_tri(float nor[3], /* XXX does not support force jacobians yet, * since the effector system does not provide them either. */ -void BPH_mass_spring_force_face_wind( +void SIM_mass_spring_force_face_wind( Implicit_Data *data, int v1, int v2, int v3, const float (*winvec)[3]) { const float effector_scale = 0.02f; @@ -856,7 +856,7 @@ void BPH_mass_spring_force_face_wind( madd_v3_v3fl(data->F.v3(v3), nor, factor * dot_v3v3(win, nor)); } -void BPH_mass_spring_force_edge_wind(Implicit_Data *data, int v1, int v2, const float (*winvec)[3]) +void SIM_mass_spring_force_edge_wind(Implicit_Data *data, int v1, int v2, const float (*winvec)[3]) { const float effector_scale = 0.01; float win[3], dir[3], nor[3], length; @@ -1000,7 +1000,7 @@ BLI_INLINE void apply_spring( data->idFdV.sub(j, i, dfdv); } -bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, +bool SIM_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, float restlen, @@ -1063,7 +1063,7 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, } /* See "Stable but Responsive Cloth" (Choi, Ko 2005) */ -bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, +bool SIM_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, float restlen, @@ -1293,7 +1293,7 @@ BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data, /* Angular spring that pulls the vertex toward the local target * See "Artistic Simulation of Curly Hair" (Pixar technical memo #12-03a) */ -bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, +bool SIM_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, int j, int k, @@ -1444,7 +1444,7 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, return true; } -bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, +bool SIM_mass_spring_force_spring_goal(Implicit_Data *data, int i, const float goal_x[3], const float goal_v[3], -- cgit v1.2.3