diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2014-08-26 20:10:12 +0400 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2015-01-20 11:29:21 +0300 |
commit | 4cd6111159715f8efb52d7ce38f99d0bdb8f0cb5 (patch) | |
tree | 206ccc2a64135b348141a76a597bbc9966799e23 /source/blender/blenkernel/intern/implicit.c | |
parent | 9e5c3a1fa9130b2fc8e1863fb3a763e69976efa2 (diff) |
Code cleanup: Use a variable-sized array for the hair volume velocity
smoothing and collision code, split into multiple functions.
Diffstat (limited to 'source/blender/blenkernel/intern/implicit.c')
-rw-r--r-- | source/blender/blenkernel/intern/implicit.c | 239 |
1 files changed, 135 insertions, 104 deletions
diff --git a/source/blender/blenkernel/intern/implicit.c b/source/blender/blenkernel/intern/implicit.c index fe64af184a9..9264aa2d8b9 100644 --- a/source/blender/blenkernel/intern/implicit.c +++ b/source/blender/blenkernel/intern/implicit.c @@ -1210,28 +1210,95 @@ static float calculateVertexWindForce(const float wind[3], const float vertexnor return dot_v3v3(wind, vertexnormal); } -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: +/* ================ Volumetric Hair Interaction ================ * 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(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVector *lV, unsigned int numverts) + +/* 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 */ +static const int hair_grid_res = 10; + +static int hair_grid_size(int res) { - /* 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. - */ + return res * res * res; +} - /* 10x10x10 grid gives nice initial results */ - HairGridVert grid[10][10][10]; - HairGridVert colg[10][10][10]; - ListBase *colliders = get_collider_cache(clmd->scene, NULL, NULL); +typedef struct HairGridVert { + float velocity[3]; + float density; +} HairGridVert; + +#define HAIR_GRID_INDEX_AXIS(vec, min, max, axis) (int)((vec[axis] - min[axis]) / (max[axis] - min[axis]) * 9.99f) + +#if 0 +BLI_INLINE void hair_grid_index(lfVector *vec, int res, const float min[3], const float max[3], + float *r_i, float *r_j, float *r_k, float *r_offset) +{ + *r_i = HAIR_GRID_INDEX_AXIS(vec, min, max, 0); + *r_j = HAIR_GRID_INDEX_AXIS(vec, min, max, 1); + *r_k = HAIR_GRID_INDEX_AXIS(vec, min, max, 2); + *r_offset = i + (j + k*res)*res; +} +#endif + +BLI_INLINE int hair_grid_offset(const float vec[3], int res, const float min[3], const float max[3]) +{ + int i, j, k; + i = HAIR_GRID_INDEX_AXIS(vec, min, max, 0); + j = HAIR_GRID_INDEX_AXIS(vec, min, max, 1); + k = HAIR_GRID_INDEX_AXIS(vec, min, max, 2); + return i + (j + k*res)*res; +} + +static void hair_velocity_smoothing(const HairGridVert *hairgrid, const float gmin[3], const float gmax[3], float smoothfac, + lfVector *lF, lfVector *lX, lfVector *lV, unsigned int numverts) +{ + int size = hair_grid_size(hair_grid_res); + int v; + /* calculate forces */ + for (v = 0; v < numverts; v++) { + int offset = hair_grid_offset(lX[v], hair_grid_res, gmin, gmax); + if (offset < 0 || offset >= size) + continue; + + lF[v][0] += smoothfac * (hairgrid[offset].velocity[0] - lV[v][0]); + lF[v][1] += smoothfac * (hairgrid[offset].velocity[1] - lV[v][1]); + lF[v][2] += smoothfac * (hairgrid[offset].velocity[2] - lV[v][2]); + } +} + +static void hair_velocity_collision(const HairGridVert *collgrid, const float gmin[3], const float gmax[3], float collfac, + lfVector *lF, lfVector *lX, lfVector *lV, unsigned int numverts) +{ + int size = hair_grid_size(hair_grid_res); + int v; + /* calculate forces */ + for (v = 0; v < numverts; v++) { + int offset = hair_grid_offset(lX[v], hair_grid_res, gmin, gmax); + if (offset < 0 || offset >= size) + continue; + + if (collgrid[offset].density > 0.0f) { + lF[v][0] += collfac * (collgrid[offset].velocity[0] - lV[v][0]); + lF[v][1] += collfac * (collgrid[offset].velocity[1] - lV[v][1]); + lF[v][2] += collfac * (collgrid[offset].velocity[2] - lV[v][2]); + } + } +} + +static void hair_volume_forces(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVector *lV, unsigned int numverts) +{ + int size = hair_grid_size(hair_grid_res); + HairGridVert *hairgrid; + HairGridVert *collgrid; + ListBase *colliders; ColliderCache *col = NULL; float gmin[3], gmax[3], density; /* 2.0f is an experimental value that seems to give good results */ @@ -1239,115 +1306,79 @@ static void hair_velocity_smoothing(ClothModifierData *clmd, lfVector *lF, lfVec float collfac = 2.0f * clmd->sim_parms->collider_friction; unsigned int v = 0; int i = 0; - int j = 0; - int k = 0; INIT_MINMAX(gmin, gmax); - for (i = 0; i < numverts; i++) DO_MINMAX(lX[i], gmin, gmax); + hairgrid = MEM_mallocN(sizeof(HairGridVert) * size, "hair voxel data"); + collgrid = MEM_mallocN(sizeof(HairGridVert) * size, "hair collider voxel data"); + /* initialize grid */ - for (i = 0; i < 10; i++) { - for (j = 0; j < 10; j++) { - for (k = 0; k < 10; k++) { - grid[i][j][k].velocity[0] = 0.0f; - 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; - } - } + for (i = 0; i < size; ++i) { + zero_v3(hairgrid[i].velocity); + hairgrid[i].density = 0.0f; + + zero_v3(collgrid[i].velocity); + collgrid[i].density = 0.0f; } /* gather velocities & density */ - 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); - if (i < 0 || j < 0 || k < 0 || i >= 10 || j >= 10 || k >= 10) - continue; - - grid[i][j][k].velocity[0] += lV[v][0]; - grid[i][j][k].velocity[1] += lV[v][1]; - grid[i][j][k].velocity[2] += lV[v][2]; - grid[i][j][k].density += 1.0f; + if (smoothfac > 0.0f) { + for (v = 0; v < numverts; v++) { + int offset = hair_grid_offset(lX[v], hair_grid_res, gmin, gmax); + if (offset < 0 || offset >= size) + continue; + + add_v3_v3(hairgrid[offset].velocity, lV[v]); + hairgrid[offset].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) { - sub_v3_v3v3(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.0f; - } - } + colliders = get_collider_cache(clmd->scene, NULL, NULL); + 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++) { + int offset = hair_grid_offset(loc1->co, hair_grid_res, gmin, gmax); + if (offset < 0 || offset >= size) + continue; + + sub_v3_v3v3(vel, loc1->co, loc0->co); + + add_v3_v3(collgrid[offset].velocity, vel); + collgrid[offset].density += 1.0f; } } } - + free_collider_cache(&colliders); /* divide velocity with density */ - for (i = 0; i < 10; i++) { - for (j = 0; j < 10; j++) { - for (k = 0; k < 10; k++) { - density = grid[i][j][k].density; - if (density > 0.0f) { - grid[i][j][k].velocity[0] /= density; - 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; - } - } + for (i = 0; i < size; i++) { + density = hairgrid[i].density; + if (density > 0.0f) { + hairgrid[i].velocity[0] /= density; + hairgrid[i].velocity[1] /= density; + hairgrid[i].velocity[2] /= density; } - } - - /* calculate forces */ - 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); - if (i < 0 || j < 0 || k < 0 || i >= 10 || j >= 10 || k >= 10) - continue; - - 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]); + + density = collgrid[i].density; + if (density > 0.0f) { + collgrid[i].velocity[0] /= density; + collgrid[i].velocity[1] /= density; + collgrid[i].velocity[2] /= density; } } - free_collider_cache(&colliders); + hair_velocity_smoothing(hairgrid, gmin, gmax, smoothfac, lF, lX, lV, numverts); + hair_velocity_collision(collgrid, gmin, gmax, collfac, lF, lX, lV, numverts); + + MEM_freeN(hairgrid); + MEM_freeN(collgrid); } static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), lfVector *lF, lfVector *lX, lfVector *lV, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, ListBase *effectors, float time, fmatrix3x3 *M) @@ -1380,7 +1411,7 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), lfVec init_lfvector(lF, gravity, numverts); if (clmd->sim_parms->velocity_smooth > 0.0f || clmd->sim_parms->collider_friction > 0.0f) - hair_velocity_smoothing(clmd, lF, lX, lV, numverts); + hair_volume_forces(clmd, lF, lX, lV, numverts); /* multiply lF with mass matrix * force = mass * acceleration (in this case: gravity) |