From bf96400558db9e8e79a00a73eba99a1ca008231f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Thu, 6 Nov 2014 14:05:32 +0100 Subject: Use a fixed, uniform cell size for hair continuum grids. This is a bit more awkward for artists to use, but necessary for a stable solution of the hair continuum calculation. The grid size is defined by the user, the extent of the grid is then calculated based on the hair geometry. A hard upper limit prevents bad memory allocation in case too small values are entered. Conflicts: source/blender/physics/intern/BPH_mass_spring.cpp --- source/blender/physics/intern/BPH_mass_spring.cpp | 23 ++-- source/blender/physics/intern/hair_volume.c | 160 +++++++++++----------- source/blender/physics/intern/implicit.h | 6 +- 3 files changed, 95 insertions(+), 94 deletions(-) (limited to 'source/blender/physics') diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp index 15693965fe0..45032b1f233 100644 --- a/source/blender/physics/intern/BPH_mass_spring.cpp +++ b/source/blender/physics/intern/BPH_mass_spring.cpp @@ -584,7 +584,7 @@ static void cloth_calc_volume_force(ClothModifierData *clmd) #endif /* returns active vertexes' motion state, or original location the vertex is disabled */ -BLI_INLINE bool cloth_get_grid_location(Implicit_Data *data, const float cell_scale[3], const float cell_offset[3], +BLI_INLINE bool cloth_get_grid_location(Implicit_Data *data, float cell_scale, const float cell_offset[3], ClothVertex *vert, int index, float x[3], float v[3]) { bool is_motion_state; @@ -592,7 +592,7 @@ BLI_INLINE bool cloth_get_grid_location(Implicit_Data *data, const float cell_sc BPH_mass_spring_get_new_velocity(data, index, v); is_motion_state = true; - mul_v3_v3(x, cell_scale); + mul_v3_fl(x, cell_scale); add_v3_v3(x, cell_offset); return is_motion_state; @@ -618,7 +618,7 @@ BLI_INLINE LinkNode *hair_spring_next(LinkNode *spring_link) * (3,4), (2,3), (1,2) * This is currently the only way to figure out hair geometry inside this code ... */ -static LinkNode *cloth_continuum_add_hair_segments(HairGrid *grid, const float cell_scale[3], const float cell_offset[3], Cloth *cloth, LinkNode *spring_link) +static LinkNode *cloth_continuum_add_hair_segments(HairGrid *grid, const float cell_scale, const float cell_offset[3], Cloth *cloth, LinkNode *spring_link) { Implicit_Data *data = cloth->implicit; LinkNode *next_spring_link = NULL; /* return value */ @@ -723,16 +723,14 @@ static void cloth_continuum_fill_grid(HairGrid *grid, Cloth *cloth) } #else LinkNode *link; - float cellsize[3], gmin[3], cell_scale[3], cell_offset[3]; + float cellsize, gmin[3], cell_scale, cell_offset[3]; /* scale and offset for transforming vertex locations into grid space * (cell size is 0..1, gmin becomes origin) */ - BPH_hair_volume_grid_geometry(grid, cellsize, NULL, gmin, NULL); - cell_scale[0] = cellsize[0] > 0.0f ? 1.0f / cellsize[0] : 0.0f; - cell_scale[1] = cellsize[1] > 0.0f ? 1.0f / cellsize[1] : 0.0f; - cell_scale[2] = cellsize[2] > 0.0f ? 1.0f / cellsize[2] : 0.0f; - mul_v3_v3v3(cell_offset, gmin, cell_scale); + BPH_hair_volume_grid_geometry(grid, &cellsize, NULL, gmin, NULL); + cell_scale = cellsize > 0.0f ? 1.0f / cellsize : 0.0f; + mul_v3_v3fl(cell_offset, gmin, cell_scale); negate_v3(cell_offset); link = cloth->springs; @@ -760,7 +758,6 @@ static void cloth_continuum_step(ClothModifierData *clmd) float pressfac = parms->pressure; float minpress = parms->pressure_threshold; float gmin[3], gmax[3]; - float cellsize[3]; int i; /* clear grid info */ @@ -772,11 +769,9 @@ static void cloth_continuum_step(ClothModifierData *clmd) /* gather velocities & density */ if (smoothfac > 0.0f || pressfac > 0.0f) { - HairGrid *grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_res, gmin, gmax); + HairGrid *grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_cell_size, gmin, gmax); BPH_hair_volume_set_debug_data(grid, clmd->debug_data); - BPH_hair_volume_grid_geometry(grid, cellsize, NULL, NULL, NULL); - cloth_continuum_fill_grid(grid, cloth); for (i = 0, vert = cloth->verts; i < numverts; i++, vert++) { @@ -1010,7 +1005,7 @@ bool BPH_cloth_solver_get_texture_data(Object *UNUSED(ob), ClothModifierData *cl hair_get_boundbox(clmd, gmin, gmax); - grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_res, gmin, gmax); + grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_cell_size, gmin, gmax); cloth_continuum_fill_grid(grid, cloth); BPH_hair_volume_get_texture_data(grid, vd); diff --git a/source/blender/physics/intern/hair_volume.c b/source/blender/physics/intern/hair_volume.c index 77c3af345c6..0713878239f 100644 --- a/source/blender/physics/intern/hair_volume.c +++ b/source/blender/physics/intern/hair_volume.c @@ -66,15 +66,9 @@ static float I[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; -static int hair_grid_size(int res) +BLI_INLINE int hair_grid_size(const int res[3]) { - return res * res * res; -} - -BLI_INLINE void hair_grid_get_scale(int res, const float gmin[3], const float gmax[3], float scale[3]) -{ - sub_v3_v3v3(scale, gmax, gmin); - mul_v3_fl(scale, 1.0f / (res-1)); + return res[0] * res[1] * res[2]; } typedef struct HairGridVert { @@ -86,36 +80,36 @@ typedef struct HairGridVert { typedef struct HairGrid { HairGridVert *verts; - int res; + int res[3]; float gmin[3], gmax[3]; - float scale[3]; + float cellsize, inv_cellsize; struct SimDebugData *debug_data; } HairGrid; -#define HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, axis) ( min_ii( max_ii( (int)((vec[axis] - gmin[axis]) / scale[axis]), 0), res-2 ) ) +#define HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, axis) ( min_ii( max_ii( (int)((vec[axis] - gmin[axis]) * scale), 0), res[axis]-2 ) ) -BLI_INLINE int hair_grid_offset(const float vec[3], int res, const float gmin[3], const float scale[3]) +BLI_INLINE int hair_grid_offset(const float vec[3], const int res[3], const float gmin[3], float scale) { int i, j, k; i = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 0); j = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 1); k = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 2); - return i + (j + k*res)*res; + return i + (j + k*res[1])*res[0]; } -BLI_INLINE int hair_grid_interp_weights(int res, const float gmin[3], const float scale[3], const float vec[3], float uvw[3]) +BLI_INLINE int hair_grid_interp_weights(const int res[3], const float gmin[3], float scale, const float vec[3], float uvw[3]) { int i, j, k, offset; i = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 0); j = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 1); k = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 2); - offset = i + (j + k*res)*res; + offset = i + (j + k*res[1])*res[0]; - uvw[0] = (vec[0] - gmin[0]) / scale[0] - (float)i; - uvw[1] = (vec[1] - gmin[1]) / scale[1] - (float)j; - uvw[2] = (vec[2] - gmin[2]) / scale[2] - (float)k; + uvw[0] = (vec[0] - gmin[0]) * scale - (float)i; + uvw[1] = (vec[1] - gmin[1]) * scale - (float)j; + uvw[2] = (vec[2] - gmin[2]) * scale - (float)k; // BLI_assert(0.0f <= uvw[0] && uvw[0] <= 1.0001f); // BLI_assert(0.0f <= uvw[1] && uvw[1] <= 1.0001f); @@ -124,12 +118,12 @@ BLI_INLINE int hair_grid_interp_weights(int res, const float gmin[3], const floa return offset; } -BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, int res, const float gmin[3], const float scale[3], const float vec[3], +BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, const int res[3], const float gmin[3], float scale, const float vec[3], float *density, float velocity[3], float density_gradient[3], float velocity_gradient[3][3]) { HairGridVert data[8]; float uvw[3], muvw[3]; - int res2 = res * res; + int res2 = res[1] * res[0]; int offset; offset = hair_grid_interp_weights(res, gmin, scale, vec, uvw); @@ -137,14 +131,14 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, int res, const f muvw[1] = 1.0f - uvw[1]; muvw[2] = 1.0f - uvw[2]; - data[0] = grid[offset ]; - data[1] = grid[offset +1]; - data[2] = grid[offset +res ]; - data[3] = grid[offset +res+1]; - data[4] = grid[offset+res2 ]; - data[5] = grid[offset+res2 +1]; - data[6] = grid[offset+res2+res ]; - data[7] = grid[offset+res2+res+1]; + data[0] = grid[offset ]; + data[1] = grid[offset +1]; + data[2] = grid[offset +res[0] ]; + data[3] = grid[offset +res[0]+1]; + data[4] = grid[offset+res2 ]; + data[5] = grid[offset+res2 +1]; + data[6] = grid[offset+res2+res[0] ]; + data[7] = grid[offset+res2+res[0]+1]; if (density) { *density = muvw[2]*( muvw[1]*( muvw[0]*data[0].density + uvw[0]*data[1].density ) + @@ -186,31 +180,13 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, int res, const f } } -#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) -{ - int v; - /* calculate forces */ - for (v = 0; v < numverts; v++) { - int offset = hair_grid_offset(lX[v], hair_grid_res, gmin, scale); - - 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]); - } - } -} -#endif - void BPH_hair_volume_vertex_grid_forces(HairGrid *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]) { float gdensity, gvelocity[3], ggrad[3], gvelgrad[3][3], gradlen; - hair_grid_interpolate(grid->verts, grid->res, grid->gmin, grid->scale, x, &gdensity, gvelocity, ggrad, gvelgrad); + hair_grid_interpolate(grid->verts, grid->res, grid->gmin, grid->inv_cellsize, x, &gdensity, gvelocity, ggrad, gvelgrad); zero_v3(f); sub_v3_v3(gvelocity, v); @@ -231,7 +207,7 @@ void BPH_hair_volume_vertex_grid_forces(HairGrid *grid, const float x[3], const void BPH_hair_volume_grid_interpolate(HairGrid *grid, const float x[3], float *density, float velocity[3], float density_gradient[3], float velocity_gradient[3][3]) { - hair_grid_interpolate(grid->verts, grid->res, grid->gmin, grid->scale, x, density, velocity, density_gradient, velocity_gradient); + hair_grid_interpolate(grid->verts, grid->res, grid->gmin, grid->inv_cellsize, x, density, velocity, density_gradient, velocity_gradient); } void BPH_hair_volume_grid_velocity(HairGrid *grid, const float x[3], const float v[3], @@ -240,7 +216,7 @@ void BPH_hair_volume_grid_velocity(HairGrid *grid, const float x[3], const float { float gdensity, gvelocity[3], ggrad[3], gvelgrad[3][3]; - hair_grid_interpolate(grid->verts, grid->res, grid->gmin, grid->scale, x, &gdensity, gvelocity, ggrad, gvelgrad); + hair_grid_interpolate(grid->verts, grid->res, grid->gmin, grid->inv_cellsize, x, &gdensity, gvelocity, ggrad, gvelgrad); /* XXX TODO implement FLIP method and use fluid_factor to blend between FLIP and PIC */ copy_v3_v3(r_v, gvelocity); @@ -268,7 +244,7 @@ BLI_INLINE float weights_sum(const float weights[8]) } /* returns the grid array offset as well to avoid redundant calculation */ -static int hair_grid_weights(int res, const float gmin[3], const float scale[3], const float vec[3], float weights[8]) +BLI_INLINE int hair_grid_weights(const int res[3], const float gmin[3], float scale, const float vec[3], float weights[8]) { int i, j, k, offset; float uvw[3]; @@ -276,11 +252,11 @@ static int hair_grid_weights(int res, const float gmin[3], const float scale[3], i = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 0); j = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 1); k = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 2); - offset = i + (j + k*res)*res; + offset = i + (j + k*res[1])*res[0]; - uvw[0] = (vec[0] - gmin[0]) / scale[0]; - uvw[1] = (vec[1] - gmin[1]) / scale[1]; - uvw[2] = (vec[2] - gmin[2]) / scale[2]; + uvw[0] = (vec[0] - gmin[0]) * scale; + uvw[1] = (vec[1] - gmin[1]) * scale; + uvw[2] = (vec[2] - gmin[2]) * scale; weights[0] = dist_tent_v3f3(uvw, (float)i , (float)j , (float)k ); weights[1] = dist_tent_v3f3(uvw, (float)(i+1), (float)j , (float)k ); @@ -298,7 +274,7 @@ static int hair_grid_weights(int res, const float gmin[3], const float scale[3], void BPH_hair_volume_add_vertex(HairGrid *grid, const float x[3], const float v[3]) { - int res = grid->res; + const int res[3] = { grid->res[0], grid->res[1], grid->res[2] }; float weights[8]; int di, dj, dk; int offset; @@ -306,12 +282,12 @@ void BPH_hair_volume_add_vertex(HairGrid *grid, const float x[3], const float v[ if (!hair_grid_point_valid(x, grid->gmin, grid->gmax)) return; - offset = hair_grid_weights(res, grid->gmin, grid->scale, x, weights); + offset = hair_grid_weights(res, grid->gmin, grid->inv_cellsize, 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 voffset = offset + di + (dj + dk*res[1])*res[0]; int iw = di + dj*2 + dk*4; grid->verts[voffset].density += weights[iw]; @@ -348,7 +324,7 @@ BLI_INLINE int major_axis_v3(const float v[3]) BLI_INLINE void grid_to_world(HairGrid *grid, float vecw[3], const float vec[3]) { copy_v3_v3(vecw, vec); - mul_v3_v3(vecw, grid->scale); + mul_v3_fl(vecw, grid->cellsize); add_v3_v3(vecw, grid->gmin); } @@ -366,7 +342,7 @@ void BPH_hair_volume_add_segment(HairGrid *grid, { SimDebugData *debug_data = grid->debug_data; - const int res[3] = { grid->res, grid->res, grid->res }; + const int res[3] = { grid->res[0], grid->res[1], grid->res[2] }; /* find the primary direction from the major axis of the direction vector */ const int axis0 = major_axis_v3(dir2); @@ -384,7 +360,7 @@ void BPH_hair_volume_add_segment(HairGrid *grid, const int grid_start1 = (int)x2[axis1]; /* offset of cells on minor axes */ const int grid_start2 = (int)x2[axis2]; /* offset of cells on minor axes */ - const float cellsize[3] = { grid->scale[axis0], grid->scale[axis1], grid->scale[axis2] }; + const float cellsize = grid->cellsize; float shift[2] = { x2[axis1] - floorf(x2[axis1]), /* fraction of a full cell shift [0.0, 1.0) */ x2[axis2] - floorf(x2[axis2]) }; @@ -397,7 +373,7 @@ void BPH_hair_volume_add_segment(HairGrid *grid, const float radius = 1.5f; /* XXX cell size should be fixed and uniform! */ - const float dist_scale = 1.0f / cellsize[0]; + const float dist_scale = grid->inv_cellsize; HairGridVert *vert0; float loc0[3]; @@ -414,7 +390,7 @@ void BPH_hair_volume_add_segment(HairGrid *grid, loc0[axis2] = (float)k0; /* loop over all planes crossed along the primary direction */ - for (i = imin; i < imax; ++i, vert0 += stride0, loc0[axis0] += cellsize[0]) { + for (i = imin; i < imax; ++i, vert0 += stride0, loc0[axis0] += cellsize) { const int jmin = max_ii(j0, 0); const int jmax = min_ii(j0 + 5, res[axis1]); const int kmin = max_ii(k0, 0); @@ -565,27 +541,55 @@ void BPH_hair_volume_vertex_grid_filter_box(HairVertexGrid *grid, int kernel_siz } #endif -HairGrid *BPH_hair_volume_create_vertex_grid(int res, const float gmin[3], const float gmax[3]) +HairGrid *BPH_hair_volume_create_vertex_grid(float cellsize, const float gmin[3], const float gmax[3]) { - float cellsize[3], gmin_margin[3], gmax_margin[3]; + float scale; + float extent[3]; + int resmin[3], resmax[3], res[3]; + float gmin_margin[3], gmax_margin[3]; int size; HairGrid *grid; int i; - /* original cell size, before adding margin */ - hair_grid_get_scale(res, gmin, gmax, cellsize); + /* sanity check */ + if (cellsize <= 0.0f) + cellsize = 1.0f; + scale = 1.0f / cellsize; - /* add margin of 1 cell */ - res += 2; + sub_v3_v3v3(extent, gmax, gmin); + for (i = 0; i < 3; ++i) { + resmin[i] = (int)(gmin[i] * scale); + resmax[i] = (int)(gmax[i] * scale) + 1; + + /* add margin of 1 cell */ + resmin[i] -= 1; + resmax[i] += 1; + + res[i] = resmax[i] - resmin[i]; + /* sanity check: avoid null-sized grid */ + if (res[i] < 3) { + res[i] = 3; + resmax[i] = resmin[i] + 3; + } + /* sanity check: avoid too large grid size */ + if (res[i] > MAX_HAIR_GRID_RES) { + res[i] = MAX_HAIR_GRID_RES; + resmax[i] = resmin[i] + MAX_HAIR_GRID_RES; + } + + gmin_margin[i] = (float)resmin[i] * cellsize; + gmax_margin[i] = (float)resmax[i] * cellsize; + } size = hair_grid_size(res); - sub_v3_v3v3(gmin_margin, gmin, cellsize); - add_v3_v3v3(gmax_margin, gmax, cellsize); grid = MEM_callocN(sizeof(HairGrid), "hair grid"); - grid->res = res; + grid->res[0] = res[0]; + grid->res[1] = res[1]; + grid->res[2] = res[2]; copy_v3_v3(grid->gmin, gmin_margin); copy_v3_v3(grid->gmax, gmax_margin); - copy_v3_v3(grid->scale, cellsize); + grid->cellsize = cellsize; + grid->inv_cellsize = scale; grid->verts = MEM_mallocN(sizeof(HairGridVert) * size, "hair voxel data"); /* initialize grid */ @@ -611,10 +615,10 @@ void BPH_hair_volume_set_debug_data(HairGrid *grid, SimDebugData *debug_data) grid->debug_data = debug_data; } -void BPH_hair_volume_grid_geometry(HairGrid *grid, float cellsize[3], int res[3], float gmin[3], float gmax[3]) +void BPH_hair_volume_grid_geometry(HairGrid *grid, float *cellsize, int res[3], float gmin[3], float gmax[3]) { - if (cellsize) copy_v3_v3(cellsize, grid->scale); - if (res) { res[0] = res[1] = res[2] = grid->res; } + if (cellsize) *cellsize = grid->cellsize; + if (res) copy_v3_v3_int(res, grid->res); if (gmin) copy_v3_v3(gmin, grid->gmin); if (gmax) copy_v3_v3(gmax, grid->gmax); } @@ -696,9 +700,9 @@ bool BPH_hair_volume_get_texture_data(HairGrid *grid, VoxelData *vd) int totres, i; int depth; - vd->resol[0] = grid->res; - vd->resol[1] = grid->res; - vd->resol[2] = grid->res; + vd->resol[0] = grid->res[0]; + vd->resol[1] = grid->res[1]; + vd->resol[2] = grid->res[2]; totres = hair_grid_size(grid->res); diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h index eba2df411af..373a73cf53f 100644 --- a/source/blender/physics/intern/implicit.h +++ b/source/blender/physics/intern/implicit.h @@ -170,10 +170,12 @@ struct HairGrid; struct Object; struct VoxelData; -struct HairGrid *BPH_hair_volume_create_vertex_grid(int res, const float gmin[3], const float gmax[3]); +#define MAX_HAIR_GRID_RES 256 + +struct HairGrid *BPH_hair_volume_create_vertex_grid(float cellsize, const float gmin[3], const float gmax[3]); void BPH_hair_volume_free_vertex_grid(struct HairGrid *grid); void BPH_hair_volume_set_debug_data(struct HairGrid *grid, struct SimDebugData *debug_data); -void BPH_hair_volume_grid_geometry(struct HairGrid *grid, float cellsize[3], int res[3], float gmin[3], float gmax[3]); +void BPH_hair_volume_grid_geometry(struct HairGrid *grid, float *cellsize, int res[3], float gmin[3], float gmax[3]); void BPH_hair_volume_add_vertex(struct HairGrid *grid, const float x[3], const float v[3]); void BPH_hair_volume_add_segment(struct HairGrid *grid, -- cgit v1.2.3