Few small hair dynamics goodies:

* Effectors now work with hair dynamics.
* Hair dynamics has a new "Collider Friction" parameter that works similarly to internal friction except now all collision objects effect the hair velocity. Useful for quick'n'dirty interaction with objects as the calculations are really fast, but doesn't really take away the need for proper hair-object collisions.
This commit is contained in:
2010-02-26 03:24:21 +00:00
parent 59e2fdbf31
commit cf4ba30f79
4 changed files with 113 additions and 16 deletions

View File

@@ -231,6 +231,7 @@ class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel):
sub.prop(cloth, "mass")
sub.prop(cloth, "bending_stiffness", text="Bending")
sub.prop(cloth, "internal_friction", slider=True)
sub.prop(cloth, "collider_friction", slider=True)
col = split.column()

View File

@@ -1408,19 +1408,29 @@ typedef struct HairGridVert {
float velocity[3];
float density;
} HairGridVert;
#define HAIR_GRID_INDEX(vec, min, max, axis) (int)( (vec[axis] - min[axis]) / (max[axis] - min[axis]) * 9.99f );
/* Smoothing of hair velocities:
* adapted from
Volumetric Methods for Simulation and Rendering of Hair
by Lena Petrovic, Mark Henne and John Anderson
* Pixar Technical Memo #06-08, Pixar Animation Studios
*/
static void hair_velocity_smoothing(float smoothfac, lfVector *lF, lfVector *lX, lfVector *lV, int numverts)
static void hair_velocity_smoothing(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVector *lV, int numverts)
{
/* TODO: this is an initial implementation and should be made much better in due time */
/* TODO: This is an initial implementation and should be made much better in due time.
* What should at least be implemented is a grid size parameter and a smoothing kernel
* for bigger grids.
*/
/* 10x10x10 grid gives nice initial results */
HairGridVert grid[10][10][10];
HairGridVert colg[10][10][10];
ListBase *colliders = get_collider_cache(clmd->scene, NULL);
ColliderCache *col = NULL;
float gmin[3], gmax[3], density;
/* 2.0f is an experimental value that seems to give good results */
float smoothfac = 2.0f * clmd->sim_parms->velocity_smooth;
float collfac = 2.0f * clmd->sim_parms->collider_friction;
int v = 0;
int i = 0;
int j = 0;
@@ -1439,15 +1449,20 @@ static void hair_velocity_smoothing(float smoothfac, lfVector *lF, lfVector *lX,
grid[i][j][k].velocity[1] = 0.0f;
grid[i][j][k].velocity[2] = 0.0f;
grid[i][j][k].density = 0.0f;
colg[i][j][k].velocity[0] = 0.0f;
colg[i][j][k].velocity[1] = 0.0f;
colg[i][j][k].velocity[2] = 0.0f;
colg[i][j][k].density = 0.0f;
}
}
}
/* gather velocities & density */
for(v = 0; v < numverts; v++) {
i = (int)( (lX[v][0] - gmin[0]) / (gmax[0] - gmin[0]) * 9.99f );
j = (int)( (lX[v][1] - gmin[1]) / (gmax[1] - gmin[1]) * 9.99f );
k = (int)( (lX[v][2] - gmin[2]) / (gmax[2] - gmin[2]) * 9.99f );
if(smoothfac > 0.0f) for(v = 0; v < numverts; v++) {
i = HAIR_GRID_INDEX(lX[v], gmin, gmax, 0);
j = HAIR_GRID_INDEX(lX[v], gmin, gmax, 1);
k = HAIR_GRID_INDEX(lX[v], gmin, gmax, 2);
grid[i][j][k].velocity[0] += lV[v][0];
grid[i][j][k].velocity[1] += lV[v][1];
@@ -1455,6 +1470,36 @@ static void hair_velocity_smoothing(float smoothfac, lfVector *lF, lfVector *lX,
grid[i][j][k].density += 1.0f;
}
/* gather colliders */
if(colliders && collfac > 0.0f) for(col = colliders->first; col; col = col->next)
{
MVert *loc0 = col->collmd->x;
MVert *loc1 = col->collmd->xnew;
float vel[3];
for(v=0; v<col->collmd->numverts; v++, loc0++, loc1++) {
i = HAIR_GRID_INDEX(loc1->co, gmin, gmax, 0);
if(i>=0 && i<10) {
j = HAIR_GRID_INDEX(loc1->co, gmin, gmax, 1);
if(j>=0 && j<10) {
k = HAIR_GRID_INDEX(loc1->co, gmin, gmax, 2);
if(k>=0 && k<10) {
VECSUB(vel, loc1->co, loc0->co);
colg[i][j][k].velocity[0] += vel[0];
colg[i][j][k].velocity[1] += vel[1];
colg[i][j][k].velocity[2] += vel[2];
colg[i][j][k].density += 1.0;
}
}
}
}
}
/* divide velocity with density */
for(i = 0; i < 10; i++) {
for(j = 0; j < 10; j++) {
@@ -1465,21 +1510,35 @@ static void hair_velocity_smoothing(float smoothfac, lfVector *lF, lfVector *lX,
grid[i][j][k].velocity[1] /= density;
grid[i][j][k].velocity[2] /= density;
}
density = colg[i][j][k].density;
if(density > 0.0f) {
colg[i][j][k].velocity[0] /= density;
colg[i][j][k].velocity[1] /= density;
colg[i][j][k].velocity[2] /= density;
}
}
}
}
/* calculate forces */
for(v = 0; v < numverts; v++) {
i = (int)( (lX[v][0] - gmin[0]) / (gmax[0] - gmin[0]) * 9.99f );
j = (int)( (lX[v][1] - gmin[1]) / (gmax[1] - gmin[1]) * 9.99f );
k = (int)( (lX[v][2] - gmin[2]) / (gmax[2] - gmin[2]) * 9.99f );
i = HAIR_GRID_INDEX(lX[v], gmin, gmax, 0);
j = HAIR_GRID_INDEX(lX[v], gmin, gmax, 1);
k = HAIR_GRID_INDEX(lX[v], gmin, gmax, 2);
/* 2.0f is an experimental value that seems to give good results */
lF[v][0] += 2.0f * smoothfac * (grid[i][j][k].velocity[0] - lV[v][0]);
lF[v][1] += 2.0f * smoothfac * (grid[i][j][k].velocity[1] - lV[v][1]);
lF[v][2] += 2.0f * smoothfac * (grid[i][j][k].velocity[2] - lV[v][2]);
lF[v][0] += smoothfac * (grid[i][j][k].velocity[0] - lV[v][0]);
lF[v][1] += smoothfac * (grid[i][j][k].velocity[1] - lV[v][1]);
lF[v][2] += smoothfac * (grid[i][j][k].velocity[2] - lV[v][2]);
if(colg[i][j][k].density > 0.0f) {
lF[v][0] += collfac * (colg[i][j][k].velocity[0] - lV[v][0]);
lF[v][1] += collfac * (colg[i][j][k].velocity[1] - lV[v][1]);
lF[v][2] += collfac * (colg[i][j][k].velocity[2] - lV[v][2]);
}
}
free_collider_cache(&colliders);
}
static void cloth_calc_force(ClothModifierData *clmd, float frame, lfVector *lF, lfVector *lX, lfVector *lV, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, ListBase *effectors, float time, fmatrix3x3 *M)
{
@@ -1508,8 +1567,8 @@ static void cloth_calc_force(ClothModifierData *clmd, float frame, lfVector *lF,
init_lfvector(lF, gravity, numverts);
if(clmd->sim_parms->velocity_smooth > 0.0f)
hair_velocity_smoothing(clmd->sim_parms->velocity_smooth, lF, lX, lV, numverts);
if(clmd->sim_parms->velocity_smooth > 0.0f || clmd->sim_parms->collider_friction > 0.0f)
hair_velocity_smoothing(clmd, lF, lX, lV, numverts);
/* multiply lF with mass matrix
// force = mass * acceleration (in this case: gravity)
@@ -1579,6 +1638,36 @@ static void cloth_calc_force(ClothModifierData *clmd, float frame, lfVector *lF,
VECADDS(lF[mfaces[i].v4], lF[mfaces[i].v4], tmp, factor);
}
}
/* Hair has only edges */
if(cloth->numfaces == 0) {
ClothSpring *spring;
float edgevec[3]={0,0,0}; //edge vector
float edgeunnormal[3]={0,0,0}; // not-normalized-edge normal
float tmp[3]={0,0,0};
float factor = 0.01;
search = cloth->springs;
while(search) {
spring = search->link;
if(spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) {
VECSUB(edgevec, (float*)lX[spring->ij], (float*)lX[spring->kl]);
project_v3_v3v3(tmp, winvec[spring->ij], edgevec);
VECSUB(edgeunnormal, winvec[spring->ij], tmp);
/* hair doesn't stretch too much so we can use restlen pretty safely */
VECADDS(lF[spring->ij], lF[spring->ij], edgeunnormal, spring->restlen * factor);
project_v3_v3v3(tmp, winvec[spring->kl], edgevec);
VECSUB(edgeunnormal, winvec[spring->kl], tmp);
VECADDS(lF[spring->kl], lF[spring->kl], edgeunnormal, spring->restlen * factor);
}
search = search->next;
}
}
del_lfvector(winvec);
}

View File

@@ -66,6 +66,8 @@ typedef struct ClothSimSettings
float goalspring;
float goalfrict;
float velocity_smooth; /* smoothing of velocities for hair */
float collider_friction; /* friction with colliders */
int stepsPerFrame; /* Number of time steps per frame. */
int flags; /* flags, see CSIMSETT_FLAGS enum above. */
int preroll; /* How many frames of simulation to do before we start. */
@@ -76,7 +78,6 @@ typedef struct ClothSimSettings
short vgroup_struct; /* vertex group for scaling structural stiffness */
short presets; /* used for presets on GUI */
short reset;
int pad;
struct EffectorWeights *effector_weights;
} ClothSimSettings;

View File

@@ -225,6 +225,12 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Internal Friction", "");
RNA_def_property_update(prop, 0, "rna_cloth_update");
prop= RNA_def_property(srna, "collider_friction", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "collider_friction");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Collider Friction", "");
RNA_def_property_update(prop, 0, "rna_cloth_update");
/* mass */
prop= RNA_def_property(srna, "mass", PROP_FLOAT, PROP_NONE);