Improved force field effects on hair strands.
authorLukas Tönne <lukas.toenne@gmail.com>
Tue, 16 Dec 2014 18:40:29 +0000 (19:40 +0100)
committerLukas Tönne <lukas.toenne@gmail.com>
Tue, 20 Jan 2015 08:30:09 +0000 (09:30 +0100)
The previous calculation was modulated with the angle between the wind
direction and the segments, which leads to very oscillating behavior.

Now the formula includes an estimate for the geometric cross section
of a hair segment based on the incident angle and the hair thickness
(currently just the particle size). This gives a more stable behavior
and more realistic response to wind.

Conflicts:
source/blender/blenkernel/intern/particle_system.c
source/blender/physics/intern/BPH_mass_spring.cpp

source/blender/blenkernel/BKE_cloth.h
source/blender/blenkernel/intern/particle_system.c
source/blender/physics/intern/BPH_mass_spring.cpp
source/blender/physics/intern/implicit.h
source/blender/physics/intern/implicit_blender.c

index ccb45cb4de2c8735e9fda385f8967ce26b5181bd..beb4f226aeab0bda6c346be27e71a6ed0783f88b 100644 (file)
@@ -65,6 +65,7 @@ typedef struct ClothHairData {
        float loc[3];
        float rot[3][3];
        float rest_target[3]; /* rest target direction for each segment */
+       float radius;
        float bending_stiffness;
 } ClothHairData;
 
index bcd0a0318fb283712473c147ea96572fb1495fb6..93eb273fc006dab417980a04a6372cd4ae712153 100644 (file)
@@ -3007,6 +3007,7 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
        int k, hair_index;
        float hairmat[4][4];
        float max_length;
+       float hair_radius;
        
        dm = *r_dm;
        if (!dm) {
@@ -3034,6 +3035,9 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
        
        psys->clmd->sim_parms->vgroup_mass = 1;
        
+       /* XXX placeholder for more flexible future hair settings */
+       hair_radius = part->size;
+       
        /* make vgroup for pin roots etc.. */
        hair_index = 1;
        LOOP_PARTICLES {
@@ -3063,6 +3067,7 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
                                copy_v3_v3(hair->loc, root_mat[3]);
                                copy_m3_m4(hair->rot, root_mat);
                                
+                               hair->radius = hair_radius;
                                hair->bending_stiffness = bending_stiffness;
                                
                                add_v3_v3v3(mvert->co, co, co);
@@ -3083,6 +3088,7 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
                        copy_v3_v3(hair->loc, root_mat[3]);
                        copy_m3_m4(hair->rot, root_mat);
                        
+                       hair->radius = hair_radius;
                        hair->bending_stiffness = bending_stiffness;
                        
                        copy_v3_v3(mvert->co, co);
index cb30529870f17b820ce752e91c3ad1fb3ac42aac..98a04de8927efd5ce36b9b86e6c3bf5eb4ede29c 100644 (file)
@@ -497,10 +497,16 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
 \r
                /* Hair has only edges */\r
                if (cloth->numfaces == 0) {\r
+                       ClothHairData *hairdata = clmd->hairdata;\r
+                       ClothHairData *hair_ij, *hair_kl;\r
+                       \r
                        for (LinkNode *link = cloth->springs; link; link = link->next) {\r
                                ClothSpring *spring = (ClothSpring *)link->link;\r
                                if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL)\r
-                                       BPH_mass_spring_force_edge_wind(data, spring->ij, spring->kl, winvec);\r
+\r
+                                       hair_ij = &hairdata[spring->ij];\r
+                                       hair_kl = &hairdata[spring->kl];\r
+                                       BPH_mass_spring_force_edge_wind(data, si_ij, si_kl, hair_ij->radius, hair_kl->radius, winvec);\r
                        }\r
                }\r
 \r
index 7081dd507a99ab1fc93f1657068ebc12ce60c0ac..1c9dccb08edc6dae3e83600f6add7b9689472c96 100644 (file)
@@ -111,7 +111,7 @@ void BPH_mass_spring_force_extern(struct Implicit_Data *data, int i, const float
 /* Wind force, acting on a face */
 void BPH_mass_spring_force_face_wind(struct Implicit_Data *data, int v1, int v2, int v3, int v4, const float (*winvec)[3]);
 /* Wind force, acting on an edge */
-void BPH_mass_spring_force_edge_wind(struct Implicit_Data *data, int v1, int v2, const float (*winvec)[3]);
+void BPH_mass_spring_force_edge_wind(struct Implicit_Data *data, int v1, int v2, float radius1, float radius2, const float (*winvec)[3]);
 /* Linear spring force between two points */
 bool BPH_mass_spring_force_spring_linear(struct Implicit_Data *data, int i, int j, float restlen,
                                          float stiffness, float damping, bool no_compress, float clamp_force,
index cb115a2c10a7ba1784f2bdae3ead4613ce6c8db5..e6320507db0cff01cd7591d31d94908f54edd016 100644 (file)
@@ -1461,21 +1461,41 @@ void BPH_mass_spring_force_face_wind(Implicit_Data *data, int v1, int v2, int v3
        }
 }
 
-void BPH_mass_spring_force_edge_wind(Implicit_Data *data, int v1, int v2, const float (*winvec)[3])
+static void edge_wind_vertex(const float dir[3], float length, float radius, const float wind[3], float f[3], float UNUSED(dfdx[3][3]), float UNUSED(dfdv[3][3]))
 {
-       const float effector_scale = 0.01;
-       float win[3], dir[3], nor[3], length;
+       const float density = 0.01f; /* XXX arbitrary value, corresponds to effect of air density */
+       float cos_alpha, sin_alpha, cross_section;
+       float windlen = len_v3(wind);
+       
+       if (windlen == 0.0f) {
+               zero_v3(f);
+               return;
+       }
+       
+       /* angle of wind direction to edge */
+       cos_alpha = dot_v3v3(wind, dir) / windlen;
+       sin_alpha = sqrt(1.0 - cos_alpha*cos_alpha);
+       cross_section = radius * (M_PI * radius * sin_alpha + length * cos_alpha);
+       
+       mul_v3_v3fl(f, wind, density * cross_section);
+}
+
+void BPH_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;
+       float f[3], dfdx[3][3], dfdv[3][3];
        
        sub_v3_v3v3(dir, data->X[v1], data->X[v2]);
        length = normalize_v3(dir);
        
        world_to_root_v3(data, v1, win, winvec[v1]);
-       madd_v3_v3v3fl(nor, win, dir, -dot_v3v3(win, dir));
-       madd_v3_v3fl(data->F[v1], nor, effector_scale * length);
+       edge_wind_vertex(dir, length, radius1, win, f, dfdx, dfdv);
+       add_v3_v3(data->F[v1], f);
        
        world_to_root_v3(data, v2, win, winvec[v2]);
-       madd_v3_v3v3fl(nor, win, dir, -dot_v3v3(win, dir));
-       madd_v3_v3fl(data->F[v2], nor, effector_scale * length);
+       /* use -length to invert edge direction */
+       edge_wind_vertex(dir, length, radius2, win, f, dfdx, dfdv);
+       add_v3_v3(data->F[v2], f);
 }
 
 BLI_INLINE void dfdx_spring(float to[3][3], const float dir[3], float length, float L, float k)