Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/physics/BPH_mass_spring.h5
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp1715
-rw-r--r--source/blender/physics/intern/hair_volume.c46
-rw-r--r--source/blender/physics/intern/implicit.h5
-rw-r--r--source/blender/render/CMakeLists.txt1
-rw-r--r--source/blender/render/SConscript1
-rw-r--r--source/blender/render/intern/source/voxeldata.c4
7 files changed, 899 insertions, 878 deletions
diff --git a/source/blender/physics/BPH_mass_spring.h b/source/blender/physics/BPH_mass_spring.h
index 166d0402d1c..c189dea28a4 100644
--- a/source/blender/physics/BPH_mass_spring.h
+++ b/source/blender/physics/BPH_mass_spring.h
@@ -33,7 +33,10 @@ extern "C" {
#endif
struct Implicit_Data;
+struct Object;
struct ClothModifierData;
+struct ListBase;
+struct VoxelData;
typedef enum eMassSpringSolverStatus {
BPH_SOLVER_SUCCESS = (1 << 0),
@@ -50,7 +53,7 @@ void BPH_cloth_solver_free(struct ClothModifierData *clmd);
int BPH_cloth_solve(struct Object *ob, float frame, struct ClothModifierData *clmd, struct ListBase *effectors);
void BKE_cloth_solver_set_positions(struct ClothModifierData *clmd);
-bool implicit_hair_volume_get_texture_data(struct Object *UNUSED(ob), struct ClothModifierData *clmd, struct ListBase *UNUSED(effectors), struct VoxelData *vd);
+bool BPH_cloth_solver_get_texture_data(struct Object *ob, struct ClothModifierData *clmd, struct VoxelData *vd);
#ifdef __cplusplus
}
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index a894603b884..7a2d85f140d 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -1,844 +1,871 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * 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.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Lukas Toenne
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/BPH_mass_spring.c
- * \ingroup bph
- */
-
-extern "C" {
-#include "MEM_guardedalloc.h"
-
-#include "DNA_cloth_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_object_force.h"
-#include "DNA_object_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
-
-#include "BLI_math.h"
-#include "BLI_linklist.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"
-
-/* 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_ANG:
- /* angular bending combines 3 vertices */
- nondiag += 3;
- break;
-
- default:
- /* all other springs depend on 2 vertices only */
- nondiag += 1;
- break;
- }
- }
-
- return nondiag;
-}
-
-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->numverts, nondiag);
-
- for (i = 0; i < cloth->numverts; i++) {
- BPH_mass_spring_set_vertex_mass(id, i, verts[i].mass);
- }
-
- for (i = 0; i < cloth->numverts; 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 numverts = cloth->numverts, i;
- ClothHairRoot *cloth_roots = clmd->roots;
- Implicit_Data *id = cloth->implicit;
-
- for (i = 0; i < numverts; i++) {
- ClothHairRoot *root = &cloth_roots[i];
-
- BPH_mass_spring_set_rest_transform(id, i, root->rot);
- BPH_mass_spring_set_motion_state(id, i, verts[i].x, verts[i].v);
- }
-}
-
-static bool collision_response(ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, float dt, float restitution, float r_impulse[3])
-{
- Cloth *cloth = clmd->clothObject;
- int index = collpair->ap1;
- bool result = false;
-
- float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
- float epsilon2 = BLI_bvhtree_getepsilon(collmd->bvhtree);
-
- float margin_distance = collpair->distance - epsilon2;
- float mag_v_rel;
-
- zero_v3(r_impulse);
-
- if (margin_distance > 0.0f)
- return false; /* XXX tested before already? */
-
- /* only handle static collisions here */
- if ( collpair->flag & COLLISION_IN_FUTURE )
- return false;
-
- /* velocity */
- copy_v3_v3(v1, cloth->verts[index].v);
- collision_get_collider_velocity(v2_old, v2_new, collmd, collpair);
- /* relative velocity = velocity of the cloth point relative to the collider */
- sub_v3_v3v3(v_rel_old, v1, v2_old);
- sub_v3_v3v3(v_rel_new, v1, v2_new);
- /* normal component of the relative velocity */
- mag_v_rel = dot_v3v3(v_rel_old, collpair->normal);
-
- /* only valid when moving toward the collider */
- if (mag_v_rel < -ALMOST_ZERO) {
- float v_nor_old, v_nor_new;
- float v_tan_old[3], v_tan_new[3];
- float bounce, repulse;
-
- /* Collision response based on
- * "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005)
- * http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf
- */
-
- v_nor_old = mag_v_rel;
- v_nor_new = dot_v3v3(v_rel_new, collpair->normal);
-
- madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old);
- madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new);
-
- bounce = -v_nor_old * restitution;
-
- repulse = -margin_distance / dt; /* base repulsion velocity in normal direction */
- /* XXX this clamping factor is quite arbitrary ...
- * not sure if there is a more scientific approach, but seems to give good results
- */
- CLAMP(repulse, 0.0f, 4.0f * bounce);
-
- if (margin_distance < -epsilon2) {
- mul_v3_v3fl(r_impulse, collpair->normal, max_ff(repulse, bounce) - v_nor_new);
- }
- else {
- bounce = 0.0f;
- mul_v3_v3fl(r_impulse, collpair->normal, repulse - v_nor_new);
- }
-
- result = true;
- }
-
- return result;
-}
-
-/* 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, ColliderContacts *contacts, int totcolliders, float dt)
-{
- Cloth *cloth = clmd->clothObject;
- Implicit_Data *data = cloth->implicit;
- ClothVertex *verts = cloth->verts;
- int numverts = cloth->numverts;
- int i, j, v;
-
- const float ZERO[3] = {0.0f, 0.0f, 0.0f};
-
- for (v = 0; v < numverts; 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;
- }
-
- for (i = 0; i < totcolliders; ++i) {
- ColliderContacts *ct = &contacts[i];
- for (j = 0; j < ct->totcollisions; ++j) {
- CollPair *collpair = &ct->collisions[j];
-// float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - ct->ob->pd->pdef_sbdamp);
- float restitution = 0.0f;
- int v = collpair->face1;
- float impulse[3];
-
- /* pinned verts handled separately */
- if (verts[v].flags & CLOTH_VERT_FLAG_PINNED)
- continue;
-
- /* XXX cheap way of avoiding instability from multiple collisions in the same step
- * this should eventually be supported ...
- */
- if (verts[v].impulse_count > 0)
- continue;
-
- /* calculate collision response */
- if (!collision_response(clmd, ct->collmd, collpair, dt, restitution, impulse))
- continue;
-
- BPH_mass_spring_add_constraint_ndof2(data, v, collpair->normal, impulse);
- ++verts[v].impulse_count;
-
- BKE_sim_debug_data_add_dot(clmd->debug_data, collpair->pa, 0, 1, 0, "collision", hash_collpair(936, collpair));
-// BKE_sim_debug_data_add_dot(clmd->debug_data, collpair->pb, 1, 0, 0, "collision", hash_collpair(937, collpair));
-// BKE_sim_debug_data_add_line(clmd->debug_data, collpair->pa, collpair->pb, 0.7, 0.7, 0.7, "collision", hash_collpair(938, collpair));
-
- { /* DEBUG */
- float nor[3];
- mul_v3_v3fl(nor, collpair->normal, -collpair->distance);
- BKE_sim_debug_data_add_vector(clmd->debug_data, collpair->pa, nor, 1, 1, 0, "collision", hash_collpair(939, collpair));
-// BKE_sim_debug_data_add_vector(clmd->debug_data, collpair->pb, impulse, 1, 1, 0, "collision", hash_collpair(940, collpair));
-// BKE_sim_debug_data_add_vector(clmd->debug_data, collpair->pb, collpair->normal, 1, 1, 0, "collision", hash_collpair(941, collpair));
- }
- }
- }
-}
-
-/* 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->numverts, "cos cloth_calc_helper_forces");
- float *masses = (float *)MEM_callocN(sizeof(float)*cloth->numverts, "cos cloth_calc_helper_forces");
- LinkNode *node;
- ClothSpring *spring;
- ClothVertex *cv;
- int i, steps;
-
- cv = cloth->verts;
- for (i=0; i<cloth->numverts; 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->numverts; 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, float time)
-{
- Cloth *cloth = clmd->clothObject;
- ClothSimSettings *parms = clmd->sim_parms;
- Implicit_Data *data = cloth->implicit;
- ClothVertex *verts = cloth->verts;
-
- bool no_compress = parms->flags & CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS;
-
- zero_v3(s->f);
- zero_m3(s->dfdx);
- zero_m3(s->dfdv);
-
- s->flags &= ~CLOTH_SPRING_FLAG_NEEDED;
-
- // calculate force of structural + shear springs
- if ((s->type & CLOTH_SPRING_TYPE_STRUCTURAL) || (s->type & CLOTH_SPRING_TYPE_SHEAR) || (s->type & CLOTH_SPRING_TYPE_SEWING) ) {
-#ifdef CLOTH_FORCE_SPRING_STRUCTURAL
- float k, scaling;
-
- s->flags |= CLOTH_SPRING_FLAG_NEEDED;
-
- scaling = parms->structural + s->stiffness * fabsf(parms->max_struct - parms->structural);
- k = scaling / (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 tunnelling through colission objects
- BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, parms->max_sewing, s->f, s->dfdx, s->dfdv);
- }
- else {
- BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, 0.0f, s->f, s->dfdx, s->dfdv);
- }
-#endif
- }
- else if (s->type & CLOTH_SPRING_TYPE_GOAL) {
-#ifdef CLOTH_FORCE_SPRING_GOAL
- float goal_x[3], goal_v[3];
- float k, scaling;
-
- s->flags |= CLOTH_SPRING_FLAG_NEEDED;
-
- // current_position = xold + t * (newposition - xold)
- interp_v3_v3v3(goal_x, verts[s->ij].xold, verts[s->ij].xconst, time);
- sub_v3_v3v3(goal_v, verts[s->ij].xconst, verts[s->ij].xold); // distance covered over dt==1
-
- scaling = parms->goalspring + s->stiffness * fabsf(parms->max_struct - parms->goalspring);
- k = verts[s->ij].goal * scaling / (parms->avg_spring_len + FLT_EPSILON);
-
- BPH_mass_spring_force_spring_goal(data, s->ij, goal_x, goal_v, k, parms->goalfrict * 0.01f, s->f, s->dfdx, s->dfdv);
-#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->stiffness * fabsf(parms->max_bend - parms->bending);
- kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
-
- scaling = parms->bending_damping;
- cb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
-
- BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb, s->f, s->dfdx, s->dfdv);
-#endif
- }
- else if (s->type & CLOTH_SPRING_TYPE_BENDING_ANG) {
-#ifdef CLOTH_FORCE_SPRING_BEND
- float kb, cb, scaling;
-
- s->flags |= CLOTH_SPRING_FLAG_NEEDED;
-
- scaling = parms->bending + s->stiffness * fabsf(parms->max_bend - parms->bending);
- kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
-
- scaling = parms->bending_damping;
- cb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
-
- /* XXX assuming same restlen for ij and jk segments here, this can be done correctly for hair later */
- BPH_mass_spring_force_spring_bending_angular(data, s->ij, s->kl, s->mn, s->target, kb, cb);
-
- {
- 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", hash_vertex(7980, s->kl));
- BKE_sim_debug_data_add_line(clmd->debug_data, x_kl, x_mn, 0.8, 0.8, 0.8, "target", hash_vertex(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", hash_vertex(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", hash_vertex(7983, s->kl));
- }
-#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 numverts = cloth->numverts;
- int i;
-
- INIT_MINMAX(gmin, gmax);
- for (i = 0; i < numverts; i++) {
- float x[3];
- BPH_mass_spring_get_motion_state(data, i, x, NULL);
- DO_MINMAX(x, gmin, gmax);
- }
-}
-
-static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListBase *effectors, float time)
-{
- /* Collect forces and derivatives: F, dFdX, dFdV */
- Cloth *cloth = clmd->clothObject;
- 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};
- MFace *mfaces = cloth->mfaces;
- unsigned int numverts = cloth->numverts;
- ClothVertex *vert;
-
-#ifdef CLOTH_FORCE_GRAVITY
- /* global acceleration (gravitation) */
- if (clmd->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- /* scale gravity force */
- mul_v3_v3fl(gravity, clmd->scene->physics_settings.gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity);
- }
- vert = cloth->verts;
- for (i = 0; i < cloth->numverts; i++, vert++) {
- BPH_mass_spring_force_gravity(data, i, vert->mass, gravity);
- }
-#endif
-
- /* cloth_calc_volume_force(clmd); */
-
-#ifdef CLOTH_FORCE_DRAG
- BPH_mass_spring_force_drag(data, drag);
-#endif
-
- /* handle external forces like wind */
- if (effectors) {
- /* cache per-vertex forces to avoid redundant calculation */
- float (*winvec)[3] = (float (*)[3])MEM_callocN(sizeof(float) * 3 * numverts, "effector forces");
- for (i = 0; i < cloth->numverts; i++) {
- float x[3], v[3];
- EffectedPoint epoint;
-
- BPH_mass_spring_get_motion_state(data, i, x, v);
- pd_point_from_loc(clmd->scene, x, v, i, &epoint);
- pdDoEffectors(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL);
- }
-
- for (i = 0; i < cloth->numfaces; i++) {
- MFace *mf = &mfaces[i];
- BPH_mass_spring_force_face_wind(data, mf->v1, mf->v2, mf->v3, mf->v4, winvec);
- }
-
- /* Hair has only edges */
- if (cloth->numfaces == 0) {
- for (LinkNode *link = cloth->springs; link; link = link->next) {
- ClothSpring *spring = (ClothSpring *)link->link;
- if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL)
- BPH_mass_spring_force_edge_wind(data, spring->ij, spring->kl, winvec);
- }
- }
-
- 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, time);
- }
-}
-
-#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 numverts = cloth->numverts;
- 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 < numverts; 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);
-
-#if 0
- /* apply velocity filter */
- BPH_hair_volume_vertex_grid_filter_box(vertex_grid, clmd->sim_parms->voxel_filter_size);
-#endif
-
- vert = cloth->verts;
- for (i = 0; i < numverts; 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_continuum_step(ClothModifierData *clmd)
-{
- ClothSimSettings *parms = clmd->sim_parms;
- Cloth *cloth = clmd->clothObject;
- Implicit_Data *data = cloth->implicit;
- int numverts = cloth->numverts;
- ClothVertex *vert;
-
- const float fluid_factor = 0.95f; /* blend between PIC and FLIP methods */
- float smoothfac = parms->velocity_smooth;
- float pressfac = parms->pressure;
- float minpress = parms->pressure_threshold;
- 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);
-
- 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 < numverts; i++, vert++) {
- float x[3], v[3];
-
- BPH_mass_spring_get_motion_state(data, i, x, v);
- BPH_mass_spring_get_position(data, i, x);
- BPH_mass_spring_get_new_velocity(data, i, v);
- BPH_hair_volume_add_vertex(vertex_grid, x, v);
- }
- BPH_hair_volume_normalize_vertex_grid(vertex_grid);
-
-#if 0
- /* apply velocity filter */
- BPH_hair_volume_vertex_grid_filter_box(vertex_grid, clmd->sim_parms->voxel_filter_size);
-#endif
-
- vert = cloth->verts;
- for (i = 0; i < numverts; 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(vertex_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(vertex_grid, NULL, 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.45f;
-
- copy_v3_v3(offset, clmd->hair_grid_min);
- zero_v3(a);
- zero_v3(b);
-
- offset[axis] = interpf(clmd->hair_grid_max[axis], clmd->hair_grid_min[axis], shift);
- 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];
-
- for (j = 0; j < size; ++j) {
- for (i = 0; i < size; ++i) {
- float x[3], v[3], nv[3];
- 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_velocity(vertex_grid, x, v, 0.0f, nv);
-
- BKE_sim_debug_data_add_vector(clmd->debug_data, x, nv, 0.4, 0, 1, "grid velocity", hash_int_2d(hash_int_2d(i, j), 3112));
- }
- }
- }
-#endif
-
- BPH_hair_volume_free_vertex_grid(vertex_grid);
- }
-}
-
-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, int steps)
-{
- 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 / (float)steps;
- }
-
- 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 / (float)steps;
- }
- 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 / (float)steps;
- }
-
- sres->min_iterations = sres->max_iterations = result->iterations;
- sres->avg_iterations += (float)result->iterations / (float)steps;
- }
-
- sres->status |= result->status;
-}
-
-int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors)
-{
- unsigned int i=0;
- float step=0.0f, tf=clmd->sim_parms->timescale;
- Cloth *cloth = clmd->clothObject;
- ClothVertex *verts = cloth->verts/*, *cv*/;
- unsigned int numverts = cloth->numverts;
- float dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame;
- Implicit_Data *id = cloth->implicit;
- ColliderContacts *contacts = NULL;
- int totcolliders = 0;
-
- BPH_mass_spring_solver_debug_data(id, clmd->debug_data);
-
- BKE_sim_debug_data_clear_category(clmd->debug_data, "collision");
-
- if (!clmd->solver_result)
- clmd->solver_result = (ClothSolverResult *)MEM_callocN(sizeof(ClothSolverResult), "cloth solver result");
- cloth_clear_result(clmd);
-
- if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) { /* do goal stuff */
- for (i = 0; i < numverts; 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);
- BPH_mass_spring_set_velocity(id, i, v);
- }
- }
- }
-
- if (clmd->debug_data) {
- for (i = 0; i < numverts; i++) {
-// BKE_sim_debug_data_add_dot(clmd->debug_data, verts[i].x, 1.0f, 0.1f, 1.0f, "points", hash_vertex(583, i));
- }
- }
-
- while (step < tf) {
- ImplicitSolverResult result;
-
- /* initialize forces to zero */
- BPH_mass_spring_clear_forces(id);
- BPH_mass_spring_clear_constraints(id);
-
- /* copy velocities for collision */
- for (i = 0; i < numverts; i++) {
- BPH_mass_spring_get_motion_state(id, i, NULL, verts[i].tv);
- copy_v3_v3(verts[i].v, verts[i].tv);
- }
-
- /* determine contact points */
- if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
- if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_POINTS) {
- cloth_find_point_contacts(ob, clmd, 0.0f, tf, &contacts, &totcolliders);
- }
- }
-
- /* setup vertex constraints for pinned vertices and contacts */
- cloth_setup_constraints(clmd, contacts, totcolliders, dt);
-
- // damping velocity for artistic reasons
- // this is a bad way to do it, should be removed imo - lukas_t
- if (clmd->sim_parms->vel_damping != 1.0f) {
- for (i = 0; i < numverts; i++) {
- float v[3];
- BPH_mass_spring_get_motion_state(id, i, NULL, v);
- mul_v3_fl(v, clmd->sim_parms->vel_damping);
- BPH_mass_spring_set_velocity(id, i, v);
- }
- }
-
- // calculate forces
- cloth_calc_force(clmd, frame, effectors, step);
-
- // calculate new velocity and position
- BPH_mass_spring_solve_velocities(id, dt, &result);
- cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame);
-
- cloth_continuum_step(clmd);
-
- BPH_mass_spring_solve_positions(id, dt);
-
- BPH_mass_spring_apply_result(id);
-
- /* move pinned verts to correct position */
- for (i = 0; i < numverts; i++) {
- if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) {
- if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
- float x[3];
- interp_v3_v3v3(x, verts[i].xold, verts[i].xconst, step + dt);
- BPH_mass_spring_set_position(id, i, x);
- }
- }
-
- BPH_mass_spring_get_motion_state(id, i, verts[i].txold, NULL);
-
-// if (!(verts[i].flags & CLOTH_VERT_FLAG_PINNED) && i > 0) {
-// BKE_sim_debug_data_add_line(clmd->debug_data, id->X[i], id->X[i-1], 0.6, 0.3, 0.3, "hair", hash_vertex(4892, i));
-// BKE_sim_debug_data_add_line(clmd->debug_data, id->Xnew[i], id->Xnew[i-1], 1, 0.5, 0.5, "hair", hash_vertex(4893, i));
-// }
-// BKE_sim_debug_data_add_vector(clmd->debug_data, id->X[i], id->V[i], 0, 0, 1, "velocity", hash_vertex(3158, i));
- }
-
- /* free contact points */
- if (contacts) {
- cloth_free_contacts(contacts, totcolliders);
- }
-
- step += dt;
- }
-
- /* copy results back to cloth data */
- for (i = 0; i < numverts; i++) {
- BPH_mass_spring_get_motion_state(id, i, verts[i].x, verts[i].v);
- copy_v3_v3(verts[i].txold, verts[i].x);
- }
-
- BPH_mass_spring_solver_debug_data(id, NULL);
-
- return 1;
-}
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/BPH_mass_spring.c
+ * \ingroup bph
+ */
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "DNA_cloth_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_force.h"
+#include "DNA_object_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BLI_math.h"
+#include "BLI_linklist.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"
+
+/* 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_ANG:
+ /* angular bending combines 3 vertices */
+ nondiag += 3;
+ break;
+
+ default:
+ /* all other springs depend on 2 vertices only */
+ nondiag += 1;
+ break;
+ }
+ }
+
+ return nondiag;
+}
+
+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->numverts, nondiag);
+
+ for (i = 0; i < cloth->numverts; i++) {
+ BPH_mass_spring_set_vertex_mass(id, i, verts[i].mass);
+ }
+
+ for (i = 0; i < cloth->numverts; 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 numverts = cloth->numverts, i;
+ ClothHairRoot *cloth_roots = clmd->roots;
+ Implicit_Data *id = cloth->implicit;
+
+ for (i = 0; i < numverts; i++) {
+ ClothHairRoot *root = &cloth_roots[i];
+
+ BPH_mass_spring_set_rest_transform(id, i, root->rot);
+ BPH_mass_spring_set_motion_state(id, i, verts[i].x, verts[i].v);
+ }
+}
+
+static bool collision_response(ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, float dt, float restitution, float r_impulse[3])
+{
+ Cloth *cloth = clmd->clothObject;
+ int index = collpair->ap1;
+ bool result = false;
+
+ float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
+ float epsilon2 = BLI_bvhtree_getepsilon(collmd->bvhtree);
+
+ float margin_distance = collpair->distance - epsilon2;
+ float mag_v_rel;
+
+ zero_v3(r_impulse);
+
+ if (margin_distance > 0.0f)
+ return false; /* XXX tested before already? */
+
+ /* only handle static collisions here */
+ if ( collpair->flag & COLLISION_IN_FUTURE )
+ return false;
+
+ /* velocity */
+ copy_v3_v3(v1, cloth->verts[index].v);
+ collision_get_collider_velocity(v2_old, v2_new, collmd, collpair);
+ /* relative velocity = velocity of the cloth point relative to the collider */
+ sub_v3_v3v3(v_rel_old, v1, v2_old);
+ sub_v3_v3v3(v_rel_new, v1, v2_new);
+ /* normal component of the relative velocity */
+ mag_v_rel = dot_v3v3(v_rel_old, collpair->normal);
+
+ /* only valid when moving toward the collider */
+ if (mag_v_rel < -ALMOST_ZERO) {
+ float v_nor_old, v_nor_new;
+ float v_tan_old[3], v_tan_new[3];
+ float bounce, repulse;
+
+ /* Collision response based on
+ * "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005)
+ * http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf
+ */
+
+ v_nor_old = mag_v_rel;
+ v_nor_new = dot_v3v3(v_rel_new, collpair->normal);
+
+ madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old);
+ madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new);
+
+ bounce = -v_nor_old * restitution;
+
+ repulse = -margin_distance / dt; /* base repulsion velocity in normal direction */
+ /* XXX this clamping factor is quite arbitrary ...
+ * not sure if there is a more scientific approach, but seems to give good results
+ */
+ CLAMP(repulse, 0.0f, 4.0f * bounce);
+
+ if (margin_distance < -epsilon2) {
+ mul_v3_v3fl(r_impulse, collpair->normal, max_ff(repulse, bounce) - v_nor_new);
+ }
+ else {
+ bounce = 0.0f;
+ mul_v3_v3fl(r_impulse, collpair->normal, repulse - v_nor_new);
+ }
+
+ result = true;
+ }
+
+ return result;
+}
+
+/* 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, ColliderContacts *contacts, int totcolliders, float dt)
+{
+ Cloth *cloth = clmd->clothObject;
+ Implicit_Data *data = cloth->implicit;
+ ClothVertex *verts = cloth->verts;
+ int numverts = cloth->numverts;
+ int i, j, v;
+
+ const float ZERO[3] = {0.0f, 0.0f, 0.0f};
+
+ for (v = 0; v < numverts; 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;
+ }
+
+ for (i = 0; i < totcolliders; ++i) {
+ ColliderContacts *ct = &contacts[i];
+ for (j = 0; j < ct->totcollisions; ++j) {
+ CollPair *collpair = &ct->collisions[j];
+// float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - ct->ob->pd->pdef_sbdamp);
+ float restitution = 0.0f;
+ int v = collpair->face1;
+ float impulse[3];
+
+ /* pinned verts handled separately */
+ if (verts[v].flags & CLOTH_VERT_FLAG_PINNED)
+ continue;
+
+ /* XXX cheap way of avoiding instability from multiple collisions in the same step
+ * this should eventually be supported ...
+ */
+ if (verts[v].impulse_count > 0)
+ continue;
+
+ /* calculate collision response */
+ if (!collision_response(clmd, ct->collmd, collpair, dt, restitution, impulse))
+ continue;
+
+ BPH_mass_spring_add_constraint_ndof2(data, v, collpair->normal, impulse);
+ ++verts[v].impulse_count;
+
+ BKE_sim_debug_data_add_dot(clmd->debug_data, collpair->pa, 0, 1, 0, "collision", hash_collpair(936, collpair));
+// BKE_sim_debug_data_add_dot(clmd->debug_data, collpair->pb, 1, 0, 0, "collision", hash_collpair(937, collpair));
+// BKE_sim_debug_data_add_line(clmd->debug_data, collpair->pa, collpair->pb, 0.7, 0.7, 0.7, "collision", hash_collpair(938, collpair));
+
+ { /* DEBUG */
+ float nor[3];
+ mul_v3_v3fl(nor, collpair->normal, -collpair->distance);
+ BKE_sim_debug_data_add_vector(clmd->debug_data, collpair->pa, nor, 1, 1, 0, "collision", hash_collpair(939, collpair));
+// BKE_sim_debug_data_add_vector(clmd->debug_data, collpair->pb, impulse, 1, 1, 0, "collision", hash_collpair(940, collpair));
+// BKE_sim_debug_data_add_vector(clmd->debug_data, collpair->pb, collpair->normal, 1, 1, 0, "collision", hash_collpair(941, collpair));
+ }
+ }
+ }
+}
+
+/* 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->numverts, "cos cloth_calc_helper_forces");
+ float *masses = (float *)MEM_callocN(sizeof(float)*cloth->numverts, "cos cloth_calc_helper_forces");
+ LinkNode *node;
+ ClothSpring *spring;
+ ClothVertex *cv;
+ int i, steps;
+
+ cv = cloth->verts;
+ for (i=0; i<cloth->numverts; 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->numverts; 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, float time)
+{
+ Cloth *cloth = clmd->clothObject;
+ ClothSimSettings *parms = clmd->sim_parms;
+ Implicit_Data *data = cloth->implicit;
+ ClothVertex *verts = cloth->verts;
+
+ bool no_compress = parms->flags & CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS;
+
+ zero_v3(s->f);
+ zero_m3(s->dfdx);
+ zero_m3(s->dfdv);
+
+ s->flags &= ~CLOTH_SPRING_FLAG_NEEDED;
+
+ // calculate force of structural + shear springs
+ if ((s->type & CLOTH_SPRING_TYPE_STRUCTURAL) || (s->type & CLOTH_SPRING_TYPE_SHEAR) || (s->type & CLOTH_SPRING_TYPE_SEWING) ) {
+#ifdef CLOTH_FORCE_SPRING_STRUCTURAL
+ float k, scaling;
+
+ s->flags |= CLOTH_SPRING_FLAG_NEEDED;
+
+ scaling = parms->structural + s->stiffness * fabsf(parms->max_struct - parms->structural);
+ k = scaling / (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 tunnelling through colission objects
+ BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, parms->max_sewing, s->f, s->dfdx, s->dfdv);
+ }
+ else {
+ BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, 0.0f, s->f, s->dfdx, s->dfdv);
+ }
+#endif
+ }
+ else if (s->type & CLOTH_SPRING_TYPE_GOAL) {
+#ifdef CLOTH_FORCE_SPRING_GOAL
+ float goal_x[3], goal_v[3];
+ float k, scaling;
+
+ s->flags |= CLOTH_SPRING_FLAG_NEEDED;
+
+ // current_position = xold + t * (newposition - xold)
+ interp_v3_v3v3(goal_x, verts[s->ij].xold, verts[s->ij].xconst, time);
+ sub_v3_v3v3(goal_v, verts[s->ij].xconst, verts[s->ij].xold); // distance covered over dt==1
+
+ scaling = parms->goalspring + s->stiffness * fabsf(parms->max_struct - parms->goalspring);
+ k = verts[s->ij].goal * scaling / (parms->avg_spring_len + FLT_EPSILON);
+
+ BPH_mass_spring_force_spring_goal(data, s->ij, goal_x, goal_v, k, parms->goalfrict * 0.01f, s->f, s->dfdx, s->dfdv);
+#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->stiffness * fabsf(parms->max_bend - parms->bending);
+ kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
+
+ scaling = parms->bending_damping;
+ cb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
+
+ BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb, s->f, s->dfdx, s->dfdv);
+#endif
+ }
+ else if (s->type & CLOTH_SPRING_TYPE_BENDING_ANG) {
+#ifdef CLOTH_FORCE_SPRING_BEND
+ float kb, cb, scaling;
+
+ s->flags |= CLOTH_SPRING_FLAG_NEEDED;
+
+ scaling = parms->bending + s->stiffness * fabsf(parms->max_bend - parms->bending);
+ kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
+
+ scaling = parms->bending_damping;
+ cb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
+
+ /* XXX assuming same restlen for ij and jk segments here, this can be done correctly for hair later */
+ BPH_mass_spring_force_spring_bending_angular(data, s->ij, s->kl, s->mn, s->target, kb, cb);
+
+ {
+ 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", hash_vertex(7980, s->kl));
+ BKE_sim_debug_data_add_line(clmd->debug_data, x_kl, x_mn, 0.8, 0.8, 0.8, "target", hash_vertex(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", hash_vertex(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", hash_vertex(7983, s->kl));
+ }
+#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 numverts = cloth->numverts;
+ int i;
+
+ INIT_MINMAX(gmin, gmax);
+ for (i = 0; i < numverts; i++) {
+ float x[3];
+ BPH_mass_spring_get_motion_state(data, i, x, NULL);
+ DO_MINMAX(x, gmin, gmax);
+ }
+}
+
+static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListBase *effectors, float time)
+{
+ /* Collect forces and derivatives: F, dFdX, dFdV */
+ Cloth *cloth = clmd->clothObject;
+ 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};
+ MFace *mfaces = cloth->mfaces;
+ unsigned int numverts = cloth->numverts;
+ ClothVertex *vert;
+
+#ifdef CLOTH_FORCE_GRAVITY
+ /* global acceleration (gravitation) */
+ if (clmd->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ /* scale gravity force */
+ mul_v3_v3fl(gravity, clmd->scene->physics_settings.gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity);
+ }
+ vert = cloth->verts;
+ for (i = 0; i < cloth->numverts; i++, vert++) {
+ BPH_mass_spring_force_gravity(data, i, vert->mass, gravity);
+ }
+#endif
+
+ /* cloth_calc_volume_force(clmd); */
+
+#ifdef CLOTH_FORCE_DRAG
+ BPH_mass_spring_force_drag(data, drag);
+#endif
+
+ /* handle external forces like wind */
+ if (effectors) {
+ /* cache per-vertex forces to avoid redundant calculation */
+ float (*winvec)[3] = (float (*)[3])MEM_callocN(sizeof(float) * 3 * numverts, "effector forces");
+ for (i = 0; i < cloth->numverts; i++) {
+ float x[3], v[3];
+ EffectedPoint epoint;
+
+ BPH_mass_spring_get_motion_state(data, i, x, v);
+ pd_point_from_loc(clmd->scene, x, v, i, &epoint);
+ pdDoEffectors(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL);
+ }
+
+ for (i = 0; i < cloth->numfaces; i++) {
+ MFace *mf = &mfaces[i];
+ BPH_mass_spring_force_face_wind(data, mf->v1, mf->v2, mf->v3, mf->v4, winvec);
+ }
+
+ /* Hair has only edges */
+ if (cloth->numfaces == 0) {
+ for (LinkNode *link = cloth->springs; link; link = link->next) {
+ ClothSpring *spring = (ClothSpring *)link->link;
+ if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL)
+ BPH_mass_spring_force_edge_wind(data, spring->ij, spring->kl, winvec);
+ }
+ }
+
+ 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, time);
+ }
+}
+
+#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 numverts = cloth->numverts;
+ 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 < numverts; 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);
+
+#if 0
+ /* apply velocity filter */
+ BPH_hair_volume_vertex_grid_filter_box(vertex_grid, clmd->sim_parms->voxel_filter_size);
+#endif
+
+ vert = cloth->verts;
+ for (i = 0; i < numverts; 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_continuum_fill_grid(HairVertexGrid *grid, Cloth *cloth)
+{
+ Implicit_Data *data = cloth->implicit;
+ int numverts = cloth->numverts;
+ ClothVertex *vert;
+ int i;
+
+ for (i = 0, vert = cloth->verts; i < numverts; i++, vert++) {
+ float x[3], v[3];
+
+ BPH_mass_spring_get_position(data, i, x);
+ BPH_mass_spring_get_new_velocity(data, i, v);
+ BPH_hair_volume_add_vertex(grid, x, v);
+ }
+ BPH_hair_volume_normalize_vertex_grid(grid);
+}
+
+static void cloth_continuum_step(ClothModifierData *clmd)
+{
+ ClothSimSettings *parms = clmd->sim_parms;
+ Cloth *cloth = clmd->clothObject;
+ Implicit_Data *data = cloth->implicit;
+ int numverts = cloth->numverts;
+ ClothVertex *vert;
+
+ const float fluid_factor = 0.95f; /* blend between PIC and FLIP methods */
+ float smoothfac = parms->velocity_smooth;
+ float pressfac = parms->pressure;
+ float minpress = parms->pressure_threshold;
+ 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);
+
+ 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);
+ cloth_continuum_fill_grid(vertex_grid, cloth);
+
+#if 0
+ /* apply velocity filter */
+ BPH_hair_volume_vertex_grid_filter_box(vertex_grid, clmd->sim_parms->voxel_filter_size);
+#endif
+
+ for (i = 0, vert = cloth->verts; i < numverts; 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(vertex_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(vertex_grid, NULL, 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.45f;
+
+ copy_v3_v3(offset, clmd->hair_grid_min);
+ zero_v3(a);
+ zero_v3(b);
+
+ offset[axis] = interpf(clmd->hair_grid_max[axis], clmd->hair_grid_min[axis], shift);
+ 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];
+
+ for (j = 0; j < size; ++j) {
+ for (i = 0; i < size; ++i) {
+ float x[3], v[3], nv[3];
+ 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_velocity(vertex_grid, x, v, 0.0f, nv);
+
+ BKE_sim_debug_data_add_vector(clmd->debug_data, x, nv, 0.4, 0, 1, "grid velocity", hash_int_2d(hash_int_2d(i, j), 3112));
+ }
+ }
+ }
+#endif
+
+ BPH_hair_volume_free_vertex_grid(vertex_grid);
+ }
+}
+
+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, int steps)
+{
+ 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 / (float)steps;
+ }
+
+ 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 / (float)steps;
+ }
+ 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 / (float)steps;
+ }
+
+ sres->min_iterations = sres->max_iterations = result->iterations;
+ sres->avg_iterations += (float)result->iterations / (float)steps;
+ }
+
+ sres->status |= result->status;
+}
+
+int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors)
+{
+ unsigned int i=0;
+ float step=0.0f, tf=clmd->sim_parms->timescale;
+ Cloth *cloth = clmd->clothObject;
+ ClothVertex *verts = cloth->verts/*, *cv*/;
+ unsigned int numverts = cloth->numverts;
+ float dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame;
+ Implicit_Data *id = cloth->implicit;
+ ColliderContacts *contacts = NULL;
+ int totcolliders = 0;
+
+ BPH_mass_spring_solver_debug_data(id, clmd->debug_data);
+
+ BKE_sim_debug_data_clear_category(clmd->debug_data, "collision");
+
+ if (!clmd->solver_result)
+ clmd->solver_result = (ClothSolverResult *)MEM_callocN(sizeof(ClothSolverResult), "cloth solver result");
+ cloth_clear_result(clmd);
+
+ if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) { /* do goal stuff */
+ for (i = 0; i < numverts; 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);
+ BPH_mass_spring_set_velocity(id, i, v);
+ }
+ }
+ }
+
+ if (clmd->debug_data) {
+ for (i = 0; i < numverts; i++) {
+// BKE_sim_debug_data_add_dot(clmd->debug_data, verts[i].x, 1.0f, 0.1f, 1.0f, "points", hash_vertex(583, i));
+ }
+ }
+
+ while (step < tf) {
+ ImplicitSolverResult result;
+
+ /* initialize forces to zero */
+ BPH_mass_spring_clear_forces(id);
+ BPH_mass_spring_clear_constraints(id);
+
+ /* copy velocities for collision */
+ for (i = 0; i < numverts; i++) {
+ BPH_mass_spring_get_motion_state(id, i, NULL, verts[i].tv);
+ copy_v3_v3(verts[i].v, verts[i].tv);
+ }
+
+ /* determine contact points */
+ if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
+ if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_POINTS) {
+ cloth_find_point_contacts(ob, clmd, 0.0f, tf, &contacts, &totcolliders);
+ }
+ }
+
+ /* setup vertex constraints for pinned vertices and contacts */
+ cloth_setup_constraints(clmd, contacts, totcolliders, dt);
+
+ // damping velocity for artistic reasons
+ // this is a bad way to do it, should be removed imo - lukas_t
+ if (clmd->sim_parms->vel_damping != 1.0f) {
+ for (i = 0; i < numverts; i++) {
+ float v[3];
+ BPH_mass_spring_get_motion_state(id, i, NULL, v);
+ mul_v3_fl(v, clmd->sim_parms->vel_damping);
+ BPH_mass_spring_set_velocity(id, i, v);
+ }
+ }
+
+ // calculate forces
+ cloth_calc_force(clmd, frame, effectors, step);
+
+ // calculate new velocity and position
+ BPH_mass_spring_solve_velocities(id, dt, &result);
+ cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame);
+
+ cloth_continuum_step(clmd);
+
+ BPH_mass_spring_solve_positions(id, dt);
+
+ BPH_mass_spring_apply_result(id);
+
+ /* move pinned verts to correct position */
+ for (i = 0; i < numverts; i++) {
+ if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) {
+ if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
+ float x[3];
+ interp_v3_v3v3(x, verts[i].xold, verts[i].xconst, step + dt);
+ BPH_mass_spring_set_position(id, i, x);
+ }
+ }
+
+ BPH_mass_spring_get_motion_state(id, i, verts[i].txold, NULL);
+
+// if (!(verts[i].flags & CLOTH_VERT_FLAG_PINNED) && i > 0) {
+// BKE_sim_debug_data_add_line(clmd->debug_data, id->X[i], id->X[i-1], 0.6, 0.3, 0.3, "hair", hash_vertex(4892, i));
+// BKE_sim_debug_data_add_line(clmd->debug_data, id->Xnew[i], id->Xnew[i-1], 1, 0.5, 0.5, "hair", hash_vertex(4893, i));
+// }
+// BKE_sim_debug_data_add_vector(clmd->debug_data, id->X[i], id->V[i], 0, 0, 1, "velocity", hash_vertex(3158, i));
+ }
+
+ /* free contact points */
+ if (contacts) {
+ cloth_free_contacts(contacts, totcolliders);
+ }
+
+ step += dt;
+ }
+
+ /* copy results back to cloth data */
+ for (i = 0; i < numverts; i++) {
+ BPH_mass_spring_get_motion_state(id, i, verts[i].x, verts[i].v);
+ copy_v3_v3(verts[i].txold, verts[i].x);
+ }
+
+ BPH_mass_spring_solver_debug_data(id, NULL);
+
+ return 1;
+}
+
+bool BPH_cloth_solver_get_texture_data(Object *UNUSED(ob), ClothModifierData *clmd, VoxelData *vd)
+{
+ Cloth *cloth = clmd->clothObject;
+ HairVertexGrid *grid;
+ float gmin[3], gmax[3];
+
+ if (!clmd->clothObject || !clmd->clothObject->implicit)
+ return false;
+
+ hair_get_boundbox(clmd, gmin, gmax);
+
+ grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_res, gmin, gmax);
+ cloth_continuum_fill_grid(grid, cloth);
+
+ BPH_hair_volume_get_texture_data(grid, vd);
+
+ BPH_hair_volume_free_vertex_grid(grid);
+
+ return true;
+}
diff --git a/source/blender/physics/intern/hair_volume.c b/source/blender/physics/intern/hair_volume.c
index b5c41880268..988bf4b9024 100644
--- a/source/blender/physics/intern/hair_volume.c
+++ b/source/blender/physics/intern/hair_volume.c
@@ -34,6 +34,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "DNA_texture_types.h"
+
#include "implicit.h"
/* ================ Volumetric Hair Interaction ================
@@ -509,30 +511,16 @@ static HairGridVert *hair_volume_create_collision_grid(ClothModifierData *clmd,
}
#endif
-#if 0
-bool implicit_hair_volume_get_texture_data(Object *UNUSED(ob), ClothModifierData *clmd, ListBase *UNUSED(effectors), VoxelData *vd)
+bool BPH_hair_volume_get_texture_data(HairVertexGrid *grid, VoxelData *vd)
{
- lfVector *lX, *lV;
- HairGridVert *hairgrid/*, *collgrid*/;
- int numverts;
int totres, i;
int depth;
- if (!clmd->clothObject || !clmd->clothObject->implicit)
- return false;
-
- lX = clmd->clothObject->implicit->X;
- lV = clmd->clothObject->implicit->V;
- numverts = clmd->clothObject->numverts;
-
- hairgrid = hair_volume_create_hair_grid(clmd, lX, lV, numverts);
-// collgrid = hair_volume_create_collision_grid(clmd, lX, numverts);
-
- vd->resol[0] = hair_grid_res;
- vd->resol[1] = hair_grid_res;
- vd->resol[2] = hair_grid_res;
+ vd->resol[0] = grid->res;
+ vd->resol[1] = grid->res;
+ vd->resol[2] = grid->res;
- totres = hair_grid_size(hair_grid_res);
+ totres = hair_grid_size(grid->res);
if (vd->hair_type == TEX_VD_HAIRVELOCITY) {
depth = 4;
@@ -549,20 +537,21 @@ bool implicit_hair_volume_get_texture_data(Object *UNUSED(ob), ClothModifierData
for (i = 0; i < totres; ++i) {
switch (vd->hair_type) {
case TEX_VD_HAIRDENSITY:
- vd->dataset[i] = hairgrid[i].density;
+ vd->dataset[i] = grid->verts[i].density;
break;
case TEX_VD_HAIRRESTDENSITY:
vd->dataset[i] = 0.0f; // TODO
break;
- case TEX_VD_HAIRVELOCITY:
- vd->dataset[i + 0*totres] = hairgrid[i].velocity[0];
- vd->dataset[i + 1*totres] = hairgrid[i].velocity[1];
- vd->dataset[i + 2*totres] = hairgrid[i].velocity[2];
- vd->dataset[i + 3*totres] = len_v3(hairgrid[i].velocity);
+ case TEX_VD_HAIRVELOCITY: {
+ float tmp = grid->verts[i].velocity[1];
+ vd->dataset[i + 0*totres] = grid->verts[i].velocity[0];
+ vd->dataset[i + 1*totres] = grid->verts[i].velocity[1];
+ vd->dataset[i + 2*totres] = grid->verts[i].velocity[2];
+ vd->dataset[i + 3*totres] = len_v3(grid->verts[i].velocity);
break;
-
+ }
case TEX_VD_HAIRENERGY:
vd->dataset[i] = 0.0f; // TODO
break;
@@ -573,10 +562,5 @@ bool implicit_hair_volume_get_texture_data(Object *UNUSED(ob), ClothModifierData
vd->dataset = NULL;
}
- MEM_freeN(hairgrid);
-// MEM_freeN(collgrid);
-
return true;
}
-
-#endif
diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h
index 9ec7e763415..b7eeea146bc 100644
--- a/source/blender/physics/intern/implicit.h
+++ b/source/blender/physics/intern/implicit.h
@@ -168,6 +168,9 @@ bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data, int i, const
struct HairVertexGrid;
struct HairColliderGrid;
+struct Object;
+struct VoxelData;
+
struct HairVertexGrid *BPH_hair_volume_create_vertex_grid(int res, const float gmin[3], const float gmax[3]);
void BPH_hair_volume_free_vertex_grid(struct HairVertexGrid *grid);
void BPH_hair_volume_grid_geometry(struct HairVertexGrid *grid, float cellsize[3], int res[3], float gmin[3], float gmax[3]);
@@ -195,6 +198,8 @@ void BPH_hair_volume_vertex_grid_forces(struct HairVertexGrid *grid, const float
float smoothfac, float pressurefac, float minpressure,
float f[3], float dfdx[3][3], float dfdv[3][3]);
+bool BPH_hair_volume_get_texture_data(struct HairVertexGrid *grid, struct VoxelData *vd);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index e516c954737..36b9f8ae362 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -33,6 +33,7 @@ set(INC
../imbuf
../makesdna
../makesrna
+ ../physics
../../../intern/guardedalloc
../../../intern/mikktspace
../../../intern/smoke/extern
diff --git a/source/blender/render/SConscript b/source/blender/render/SConscript
index ebd131082e4..0cbf188525b 100644
--- a/source/blender/render/SConscript
+++ b/source/blender/render/SConscript
@@ -40,6 +40,7 @@ incs = [
'../imbuf',
'../makesdna',
'../makesrna',
+ '../physics',
'../../../intern/mikktspace',
'../../../intern/smoke/extern',
]
diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c
index 6f3c50bca62..8bc5c7a1c8f 100644
--- a/source/blender/render/intern/source/voxeldata.c
+++ b/source/blender/render/intern/source/voxeldata.c
@@ -58,6 +58,7 @@
#include "BKE_modifier.h"
#include "smoke_API.h"
+#include "BPH_mass_spring.h"
#include "DNA_texture_types.h"
#include "DNA_object_force.h"
@@ -380,8 +381,7 @@ static void init_frame_hair(VoxelData *vd, int UNUSED(cfra))
ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md;
if (pmd->psys && pmd->psys->clmd) {
- // XXX TODO was moved into own subfolder, figure out how to handle this (perhaps make a wrapper in BKE)
-// found |= implicit_hair_volume_get_texture_data(ob, pmd->psys->clmd, NULL, vd);
+ found |= BPH_cloth_solver_get_texture_data(ob, pmd->psys->clmd, vd);
}
}