diff options
-rw-r--r-- | source/blender/physics/intern/BPH_mass_spring.cpp | 61 | ||||
-rw-r--r-- | source/blender/physics/intern/hair_volume.c | 218 | ||||
-rw-r--r-- | source/blender/physics/intern/implicit.h | 16 | ||||
-rw-r--r-- | source/blender/physics/intern/implicit_blender.c | 27 |
4 files changed, 206 insertions, 116 deletions
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp index 1c45e1ed1f8..568aea6abe3 100644 --- a/source/blender/physics/intern/BPH_mass_spring.cpp +++ b/source/blender/physics/intern/BPH_mass_spring.cpp @@ -386,6 +386,64 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, } } +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_volume_force(ClothModifierData *clmd) +{ + ClothSimSettings *parms = clmd->sim_parms; + Cloth *cloth = clmd->clothObject; + Implicit_Data *data = cloth->implicit; + int numverts = cloth->numverts; + + /* 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(gmin, gmax); + + for (i = 0; i < numverts; i++) { + float x[3], v[3]; + + BPH_mass_spring_get_motion_state(data, i, x, v); + BPH_hair_volume_add_vertex(vertex_grid, x, v); + } + BPH_hair_volume_normalize_vertex_grid(vertex_grid); + + for (i = 0; i < numverts; i++) { + float x[3], v[3], f[3], dfdx[3][3], dfdv[3][3]; + + /* calculate volumetric forces */ + BPH_mass_spring_get_motion_state(data, i, 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, i, f, dfdx, dfdv); + } + + BPH_hair_volume_free_vertex_grid(vertex_grid); + } +} + static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListBase *effectors, float time) { /* Collect forces and derivatives: F, dFdX, dFdV */ @@ -409,8 +467,7 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB BPH_mass_spring_force_gravity(data, gravity); #endif - // XXX TODO -// hair_volume_forces(clmd, lF, lX, lV, numverts); + cloth_calc_volume_force(clmd); #ifdef CLOTH_FORCE_DRAG BPH_mass_spring_force_drag(data, drag); diff --git a/source/blender/physics/intern/hair_volume.c b/source/blender/physics/intern/hair_volume.c index 5111eac3a48..c129f029873 100644 --- a/source/blender/physics/intern/hair_volume.c +++ b/source/blender/physics/intern/hair_volume.c @@ -29,10 +29,12 @@ * \ingroup bph */ +#include "MEM_guardedalloc.h" + #include "BLI_math.h" #include "BLI_utildefines.h" -#if 0 // XXX TODO +#include "implicit.h" /* ================ Volumetric Hair Interaction ================ * adapted from @@ -52,6 +54,9 @@ * for bigger grids. */ + +static float I[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; + /* 10x10x10 grid gives nice initial results */ static const int hair_grid_res = 10; @@ -71,6 +76,20 @@ typedef struct HairGridVert { float density; } HairGridVert; +typedef struct HairVertexGrid { + HairGridVert *verts; + int res; + float gmin[3], gmax[3]; + float scale[3]; +} HairVertexGrid; + +typedef struct HairColliderGrid { + HairGridVert *verts; + int res; + float gmin[3], gmax[3]; + float scale[3]; +} HairColliderGrid; + #define HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, axis) ( min_ii( max_ii( (int)((vec[axis] - gmin[axis]) / scale[axis]), 0), res-2 ) ) BLI_INLINE int hair_grid_offset(const float vec[3], int res, const float gmin[3], const float scale[3]) @@ -99,7 +118,7 @@ BLI_INLINE int hair_grid_interp_weights(int res, const float gmin[3], const floa } BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, int res, const float gmin[3], const float scale[3], const float vec[3], - float *density, float velocity[3], float density_gradient[3]) + float *density, float velocity[3], float density_gradient[3], float velocity_gradient[3][3]) { HairGridVert data[8]; float uvw[3], muvw[3]; @@ -126,6 +145,7 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, int res, const f uvw[2]*( muvw[1]*( muvw[0]*data[4].density + uvw[0]*data[5].density ) + uvw[1]*( muvw[0]*data[6].density + uvw[0]*data[7].density ) ); } + if (velocity) { int k; for (k = 0; k < 3; ++k) { @@ -135,6 +155,7 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, int res, const f uvw[1]*( muvw[0]*data[6].velocity[k] + uvw[0]*data[7].velocity[k] ) ); } } + if (density_gradient) { density_gradient[0] = muvw[1] * muvw[2] * ( data[0].density - data[1].density ) + uvw[1] * muvw[2] * ( data[2].density - data[3].density ) + @@ -151,23 +172,14 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, int res, const f muvw[2] * uvw[0] * ( data[2].density - data[6].density ) + uvw[2] * uvw[0] * ( data[3].density - data[7].density ); } -} - -static void hair_velocity_smoothing(const HairGridVert *hairgrid, const float gmin[3], const float scale[3], float smoothfac, - lfVector *lF, lfVector *lX, lfVector *lV, unsigned int numverts) -{ - int v; - /* calculate forces */ - for (v = 0; v < numverts; v++) { - float density, velocity[3]; - - hair_grid_interpolate(hairgrid, hair_grid_res, gmin, scale, lX[v], &density, velocity, NULL); - - sub_v3_v3(velocity, lV[v]); - madd_v3_v3fl(lF[v], velocity, smoothfac); + + if (velocity_gradient) { + /* XXX TODO */ + zero_m3(velocity_gradient); } } +#if 0 static void hair_velocity_collision(const HairGridVert *collgrid, const float gmin[3], const float scale[3], float collfac, lfVector *lF, lfVector *lX, lfVector *lV, unsigned int numverts) { @@ -183,34 +195,30 @@ static void hair_velocity_collision(const HairGridVert *collgrid, const float gm } } } +#endif -static void hair_pressure_force(const HairGridVert *hairgrid, const float gmin[3], const float scale[3], float pressurefac, float minpressure, - lfVector *lF, lfVector *lX, unsigned int numverts) +void BPH_hair_volume_vertex_grid_forces(HairVertexGrid *grid, const float x[3], const float v[3], + float smoothfac, float pressurefac, float minpressure, + float f[3], float dfdx[3][3], float dfdv[3][3]) { - int v; + float gdensity, gvelocity[3], ggrad[3], gvelgrad[3][3], gradlen; - /* calculate forces */ - for (v = 0; v < numverts; v++) { - float density, gradient[3], gradlen; - - hair_grid_interpolate(hairgrid, hair_grid_res, gmin, scale, lX[v], &density, NULL, gradient); - - gradlen = normalize_v3(gradient) - minpressure; - if (gradlen < 0.0f) - continue; - mul_v3_fl(gradient, gradlen); - - madd_v3_v3fl(lF[v], gradient, pressurefac); + hair_grid_interpolate(grid->verts, grid->res, grid->gmin, grid->scale, x, &gdensity, gvelocity, ggrad, gvelgrad); + + zero_v3(f); + sub_v3_v3(gvelocity, v); + mul_v3_v3fl(f, gvelocity, smoothfac); + + gradlen = normalize_v3(ggrad) - minpressure; + if (gradlen > 0.0f) { + mul_v3_fl(ggrad, gradlen); + madd_v3_v3fl(f, ggrad, pressurefac); } -} - -static void hair_volume_get_boundbox(lfVector *lX, unsigned int numverts, float gmin[3], float gmax[3]) -{ - int i; - INIT_MINMAX(gmin, gmax); - for (i = 0; i < numverts; i++) - DO_MINMAX(lX[i], gmin, gmax); + zero_m3(dfdx); + + sub_m3_m3m3(dfdv, gvelgrad, I); + mul_m3_fl(dfdv, smoothfac); } BLI_INLINE bool hair_grid_point_valid(const float vec[3], float gmin[3], float gmax[3]) @@ -252,66 +260,75 @@ static int hair_grid_weights(int res, const float gmin[3], const float scale[3], return offset; } -static HairGridVert *hair_volume_create_hair_grid(ClothModifierData *clmd, lfVector *lX, lfVector *lV, unsigned int numverts) +void BPH_hair_volume_add_vertex(HairVertexGrid *grid, const float x[3], const float v[3]) { - int res = hair_grid_res; - int size = hair_grid_size(res); - HairGridVert *hairgrid; - float gmin[3], gmax[3], scale[3]; - /* 2.0f is an experimental value that seems to give good results */ - float smoothfac = 2.0f * clmd->sim_parms->velocity_smooth; - unsigned int v = 0; - int i = 0; - - hair_volume_get_boundbox(lX, numverts, gmin, gmax); - hair_grid_get_scale(res, gmin, gmax, scale); - - hairgrid = MEM_mallocN(sizeof(HairGridVert) * size, "hair voxel data"); - - /* initialize grid */ - for (i = 0; i < size; ++i) { - zero_v3(hairgrid[i].velocity); - hairgrid[i].density = 0.0f; - } - - /* gather velocities & density */ - if (smoothfac > 0.0f) { - for (v = 0; v < numverts; v++) { - float *V = lV[v]; - float weights[8]; - int di, dj, dk; - int offset; - - if (!hair_grid_point_valid(lX[v], gmin, gmax)) - continue; - - offset = hair_grid_weights(res, gmin, scale, lX[v], weights); - - for (di = 0; di < 2; ++di) { - for (dj = 0; dj < 2; ++dj) { - for (dk = 0; dk < 2; ++dk) { - int voffset = offset + di + (dj + dk*res)*res; - int iw = di + dj*2 + dk*4; - - hairgrid[voffset].density += weights[iw]; - madd_v3_v3fl(hairgrid[voffset].velocity, V, weights[iw]); - } - } + int res = grid->res; + float weights[8]; + int di, dj, dk; + int offset; + + if (!hair_grid_point_valid(x, grid->gmin, grid->gmax)) + return; + + offset = hair_grid_weights(res, grid->gmin, grid->scale, x, weights); + + for (di = 0; di < 2; ++di) { + for (dj = 0; dj < 2; ++dj) { + for (dk = 0; dk < 2; ++dk) { + int voffset = offset + di + (dj + dk*res)*res; + int iw = di + dj*2 + dk*4; + + grid->verts[voffset].density += weights[iw]; + madd_v3_v3fl(grid->verts[voffset].velocity, v, weights[iw]); } } } +} +void BPH_hair_volume_normalize_vertex_grid(HairVertexGrid *grid) +{ + int i, size = hair_grid_size(grid->res); /* divide velocity with density */ for (i = 0; i < size; i++) { - float density = hairgrid[i].density; + float density = grid->verts[i].density; if (density > 0.0f) - mul_v3_fl(hairgrid[i].velocity, 1.0f/density); + mul_v3_fl(grid->verts[i].velocity, 1.0f/density); + } +} + +HairVertexGrid *BPH_hair_volume_create_vertex_grid(const float gmin[3], const float gmax[3]) +{ + int res = hair_grid_res; + int size = hair_grid_size(res); + HairVertexGrid *grid; + int i = 0; + + grid = MEM_callocN(sizeof(HairVertexGrid), "hair vertex grid"); + grid->res = res; + copy_v3_v3(grid->gmin, gmin); + copy_v3_v3(grid->gmax, gmax); + hair_grid_get_scale(res, gmin, gmax, grid->scale); + grid->verts = MEM_mallocN(sizeof(HairGridVert) * size, "hair voxel data"); + + /* initialize grid */ + for (i = 0; i < size; ++i) { + zero_v3(grid->verts[i].velocity); + grid->verts[i].density = 0.0f; } - return hairgrid; + return grid; } +void BPH_hair_volume_free_vertex_grid(HairVertexGrid *grid) +{ + if (grid) { + if (grid->verts) + MEM_freeN(grid->verts); + MEM_freeN(grid); + } +} +#if 0 static HairGridVert *hair_volume_create_collision_grid(ClothModifierData *clmd, lfVector *lX, unsigned int numverts) { int res = hair_grid_res; @@ -381,33 +398,7 @@ static HairGridVert *hair_volume_create_collision_grid(ClothModifierData *clmd, return collgrid; } - -static void hair_volume_forces(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVector *lV, unsigned int numverts) -{ - HairGridVert *hairgrid, *collgrid; - float gmin[3], gmax[3], scale[3]; - /* 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; - float pressfac = clmd->sim_parms->pressure; - float minpress = clmd->sim_parms->pressure_threshold; - - if (smoothfac <= 0.0f && collfac <= 0.0f && pressfac <= 0.0f) - return; - - hair_volume_get_boundbox(lX, numverts, gmin, gmax); - hair_grid_get_scale(hair_grid_res, gmin, gmax, scale); - - hairgrid = hair_volume_create_hair_grid(clmd, lX, lV, numverts); - collgrid = hair_volume_create_collision_grid(clmd, lX, numverts); - - hair_velocity_smoothing(hairgrid, gmin, scale, smoothfac, lF, lX, lV, numverts); - hair_velocity_collision(collgrid, gmin, scale, collfac, lF, lX, lV, numverts); - hair_pressure_force(hairgrid, gmin, scale, pressfac, minpress, lF, lX, numverts); - - MEM_freeN(hairgrid); - MEM_freeN(collgrid); -} +#endif #if 0 bool implicit_hair_volume_get_texture_data(Object *UNUSED(ob), ClothModifierData *clmd, ListBase *UNUSED(effectors), VoxelData *vd) @@ -478,6 +469,5 @@ bool implicit_hair_volume_get_texture_data(Object *UNUSED(ob), ClothModifierData return true; } -#endif #endif diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h index 25771740def..66ee92f950e 100644 --- a/source/blender/physics/intern/implicit.h +++ b/source/blender/physics/intern/implicit.h @@ -126,6 +126,8 @@ void BPH_mass_spring_force_reference_frame(struct Implicit_Data *data, int index void BPH_mass_spring_force_gravity(struct Implicit_Data *data, const float g[3]); /* Global drag force (velocity damping) */ void BPH_mass_spring_force_drag(struct Implicit_Data *data, float drag); +/* Custom external force */ +void BPH_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 */ 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 */ @@ -143,6 +145,20 @@ bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data, int i, int sp float stiffness, float damping, float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]); +/* ======== Hair Volumetric Forces ======== */ + +struct HairVertexGrid; +struct HairColliderGrid; + +struct HairVertexGrid *BPH_hair_volume_create_vertex_grid(const float gmin[3], const float gmax[3]); +void BPH_hair_volume_free_vertex_grid(struct HairVertexGrid *grid); + +void BPH_hair_volume_add_vertex(struct HairVertexGrid *grid, const float x[3], const float v[3]); +void BPH_hair_volume_normalize_vertex_grid(struct HairVertexGrid *grid); +void BPH_hair_volume_vertex_grid_forces(struct HairVertexGrid *grid, const float x[3], const float v[3], + float smoothfac, float pressurefac, float minpressure, + float f[3], float dfdx[3][3], float dfdv[3][3]); + #ifdef __cplusplus } #endif diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c index 0c02e648661..60237a76dc6 100644 --- a/source/blender/physics/intern/implicit_blender.c +++ b/source/blender/physics/intern/implicit_blender.c @@ -764,6 +764,21 @@ BLI_INLINE void direction_root_to_world(Implicit_Data *data, int index, float r[ mul_v3_m3v3(r, root->rot, v); } +BLI_INLINE void matrix_world_to_root(Implicit_Data *data, int index, float r[3][3], float m[3][3]) +{ + RootTransform *root = &data->root[index]; + float trot[3][3]; + copy_m3_m3(trot, root->rot); + transpose_m3(trot); + mul_m3_m3m3(r, trot, m); +} + +BLI_INLINE void matrix_root_to_world(Implicit_Data *data, int index, float r[3][3], float m[3][3]) +{ + RootTransform *root = &data->root[index]; + mul_m3_m3m3(r, root->rot, m); +} + /* ================================ */ DO_INLINE void filter(lfVector *V, fmatrix3x3 *S) @@ -1367,6 +1382,18 @@ void BPH_mass_spring_force_drag(Implicit_Data *data, float drag) } } +void BPH_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]; + direction_world_to_root(data, i, tf, f); + matrix_world_to_root(data, i, tdfdx, dfdx); + matrix_world_to_root(data, i, tdfdv, dfdv); + + add_v3_v3(data->F[i], tf); + add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, tdfdx); + add_m3_m3m3(data->dFdV[i].m, data->dFdV[i].m, tdfdv); +} + static float calc_nor_area_tri(float nor[3], const float v1[3], const float v2[3], const float v3[3]) { float n1[3], n2[3]; |