Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/physics/intern/hair_volume.cpp')
-rw-r--r--source/blender/physics/intern/hair_volume.cpp1780
1 files changed, 930 insertions, 850 deletions
diff --git a/source/blender/physics/intern/hair_volume.cpp b/source/blender/physics/intern/hair_volume.cpp
index 0eb26934b5d..878f055af01 100644
--- a/source/blender/physics/intern/hair_volume.cpp
+++ b/source/blender/physics/intern/hair_volume.cpp
@@ -57,282 +57,335 @@ static float I[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
BLI_INLINE int floor_int(float value)
{
- return value > 0.0f ? (int)value : ((int)value) - 1;
+ return value > 0.0f ? (int)value : ((int)value) - 1;
}
BLI_INLINE float floor_mod(float value)
{
- return value - floorf(value);
+ return value - floorf(value);
}
BLI_INLINE int hair_grid_size(const int res[3])
{
- return res[0] * res[1] * res[2];
+ return res[0] * res[1] * res[2];
}
typedef struct HairGridVert {
- int samples;
- float velocity[3];
- float density;
+ int samples;
+ float velocity[3];
+ float density;
- float velocity_smooth[3];
+ float velocity_smooth[3];
} HairGridVert;
typedef struct HairGrid {
- HairGridVert *verts;
- int res[3];
- float gmin[3], gmax[3];
- float cellsize, inv_cellsize;
+ HairGridVert *verts;
+ int res[3];
+ float gmin[3], gmax[3];
+ float cellsize, inv_cellsize;
} HairGrid;
-#define HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, axis) (min_ii(max_ii( (int)((vec[axis] - gmin[axis]) * scale), 0), res[axis] - 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], const int res[3], const float gmin[3], float scale)
+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[1]) * res[0];
+ 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[1]) * res[0];
}
-BLI_INLINE int hair_grid_interp_weights(const int res[3], const float gmin[3], float scale, 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;
+ 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[1]) * res[0];
+ 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[1]) * res[0];
- 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;
+ 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);
-// BLI_assert(0.0f <= uvw[2] && uvw[2] <= 1.0001f);
+ // BLI_assert(0.0f <= uvw[0] && uvw[0] <= 1.0001f);
+ // BLI_assert(0.0f <= uvw[1] && uvw[1] <= 1.0001f);
+ // BLI_assert(0.0f <= uvw[2] && uvw[2] <= 1.0001f);
- return offset;
+ return offset;
}
-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 vel_smooth[3], float density_gradient[3], float velocity_gradient[3][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 vel_smooth[3],
+ float density_gradient[3],
+ float velocity_gradient[3][3])
{
- HairGridVert data[8];
- float uvw[3], muvw[3];
- int res2 = res[1] * res[0];
- int offset;
-
- offset = hair_grid_interp_weights(res, gmin, scale, vec, uvw);
- muvw[0] = 1.0f - uvw[0];
- 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[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) +
- uvw[1] * (muvw[0] * data[2].density + uvw[0] * data[3].density)) +
- 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) {
- velocity[k] = muvw[2] * (muvw[1] * (muvw[0] * data[0].velocity[k] + uvw[0] * data[1].velocity[k]) +
- uvw[1] * (muvw[0] * data[2].velocity[k] + uvw[0] * data[3].velocity[k]) ) +
- uvw[2] * (muvw[1] * (muvw[0] * data[4].velocity[k] + uvw[0] * data[5].velocity[k]) +
- uvw[1] * (muvw[0] * data[6].velocity[k] + uvw[0] * data[7].velocity[k]) );
- }
- }
-
- if (vel_smooth) {
- int k;
- for (k = 0; k < 3; ++k) {
- vel_smooth[k] = muvw[2] * (muvw[1] * (muvw[0] * data[0].velocity_smooth[k] + uvw[0] * data[1].velocity_smooth[k]) +
- uvw[1] * (muvw[0] * data[2].velocity_smooth[k] + uvw[0] * data[3].velocity_smooth[k]) ) +
- uvw[2] * (muvw[1] * (muvw[0] * data[4].velocity_smooth[k] + uvw[0] * data[5].velocity_smooth[k]) +
- uvw[1] * (muvw[0] * data[6].velocity_smooth[k] + uvw[0] * data[7].velocity_smooth[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) +
- muvw[1] * uvw[2] * (data[4].density - data[5].density) +
- uvw[1] * uvw[2] * (data[6].density - data[7].density);
-
- density_gradient[1] = muvw[2] * muvw[0] * (data[0].density - data[2].density) +
- uvw[2] * muvw[0] * (data[4].density - data[6].density) +
- muvw[2] * uvw[0] * (data[1].density - data[3].density) +
- uvw[2] * uvw[0] * (data[5].density - data[7].density);
-
- density_gradient[2] = muvw[2] * muvw[0] * (data[0].density - data[4].density) +
- uvw[2] * muvw[0] * (data[1].density - data[5].density) +
- muvw[2] * uvw[0] * (data[2].density - data[6].density) +
- uvw[2] * uvw[0] * (data[3].density - data[7].density);
- }
-
- if (velocity_gradient) {
- /* XXX TODO */
- zero_m3(velocity_gradient);
- }
+ HairGridVert data[8];
+ float uvw[3], muvw[3];
+ int res2 = res[1] * res[0];
+ int offset;
+
+ offset = hair_grid_interp_weights(res, gmin, scale, vec, uvw);
+ muvw[0] = 1.0f - uvw[0];
+ 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[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) +
+ uvw[1] * (muvw[0] * data[2].density + uvw[0] * data[3].density)) +
+ 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) {
+ velocity[k] = muvw[2] *
+ (muvw[1] * (muvw[0] * data[0].velocity[k] + uvw[0] * data[1].velocity[k]) +
+ uvw[1] * (muvw[0] * data[2].velocity[k] + uvw[0] * data[3].velocity[k])) +
+ uvw[2] *
+ (muvw[1] * (muvw[0] * data[4].velocity[k] + uvw[0] * data[5].velocity[k]) +
+ uvw[1] * (muvw[0] * data[6].velocity[k] + uvw[0] * data[7].velocity[k]));
+ }
+ }
+
+ if (vel_smooth) {
+ int k;
+ for (k = 0; k < 3; ++k) {
+ vel_smooth[k] = muvw[2] * (muvw[1] * (muvw[0] * data[0].velocity_smooth[k] +
+ uvw[0] * data[1].velocity_smooth[k]) +
+ uvw[1] * (muvw[0] * data[2].velocity_smooth[k] +
+ uvw[0] * data[3].velocity_smooth[k])) +
+ uvw[2] * (muvw[1] * (muvw[0] * data[4].velocity_smooth[k] +
+ uvw[0] * data[5].velocity_smooth[k]) +
+ uvw[1] * (muvw[0] * data[6].velocity_smooth[k] +
+ uvw[0] * data[7].velocity_smooth[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) +
+ muvw[1] * uvw[2] * (data[4].density - data[5].density) +
+ uvw[1] * uvw[2] * (data[6].density - data[7].density);
+
+ density_gradient[1] = muvw[2] * muvw[0] * (data[0].density - data[2].density) +
+ uvw[2] * muvw[0] * (data[4].density - data[6].density) +
+ muvw[2] * uvw[0] * (data[1].density - data[3].density) +
+ uvw[2] * uvw[0] * (data[5].density - data[7].density);
+
+ density_gradient[2] = muvw[2] * muvw[0] * (data[0].density - data[4].density) +
+ uvw[2] * muvw[0] * (data[1].density - data[5].density) +
+ muvw[2] * uvw[0] * (data[2].density - data[6].density) +
+ uvw[2] * uvw[0] * (data[3].density - data[7].density);
+ }
+
+ if (velocity_gradient) {
+ /* XXX TODO */
+ zero_m3(velocity_gradient);
+ }
}
-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])
+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->inv_cellsize, x, &gdensity, gvelocity, NULL, 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);
- }
-
- zero_m3(dfdx);
-
- sub_m3_m3m3(dfdv, gvelgrad, I);
- mul_m3_fl(dfdv, smoothfac);
+ float gdensity, gvelocity[3], ggrad[3], gvelgrad[3][3], gradlen;
+
+ hair_grid_interpolate(grid->verts,
+ grid->res,
+ grid->gmin,
+ grid->inv_cellsize,
+ x,
+ &gdensity,
+ gvelocity,
+ NULL,
+ 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);
+ }
+
+ zero_m3(dfdx);
+
+ sub_m3_m3m3(dfdv, gvelgrad, I);
+ mul_m3_fl(dfdv, smoothfac);
}
-void BPH_hair_volume_grid_interpolate(
- HairGrid *grid, const float x[3],
- float *density, float velocity[3], float velocity_smooth[3], float density_gradient[3], float velocity_gradient[3][3])
+void BPH_hair_volume_grid_interpolate(HairGrid *grid,
+ const float x[3],
+ float *density,
+ float velocity[3],
+ float velocity_smooth[3],
+ float density_gradient[3],
+ float velocity_gradient[3][3])
{
- hair_grid_interpolate(grid->verts, grid->res, grid->gmin, grid->inv_cellsize, x, density, velocity, velocity_smooth, density_gradient, velocity_gradient);
+ hair_grid_interpolate(grid->verts,
+ grid->res,
+ grid->gmin,
+ grid->inv_cellsize,
+ x,
+ density,
+ velocity,
+ velocity_smooth,
+ density_gradient,
+ velocity_gradient);
}
void BPH_hair_volume_grid_velocity(
- HairGrid *grid, const float x[3], const float v[3],
- float fluid_factor,
- float r_v[3])
+ HairGrid *grid, const float x[3], const float v[3], float fluid_factor, float r_v[3])
{
- float gdensity, gvelocity[3], gvel_smooth[3], ggrad[3], gvelgrad[3][3];
- float v_pic[3], v_flip[3];
-
- hair_grid_interpolate(grid->verts, grid->res, grid->gmin, grid->inv_cellsize, x, &gdensity, gvelocity, gvel_smooth, ggrad, gvelgrad);
-
- /* velocity according to PIC method (Particle-in-Cell) */
- copy_v3_v3(v_pic, gvel_smooth);
-
- /* velocity according to FLIP method (Fluid-Implicit-Particle) */
- sub_v3_v3v3(v_flip, gvel_smooth, gvelocity);
- add_v3_v3(v_flip, v);
-
- interp_v3_v3v3(r_v, v_pic, v_flip, fluid_factor);
+ float gdensity, gvelocity[3], gvel_smooth[3], ggrad[3], gvelgrad[3][3];
+ float v_pic[3], v_flip[3];
+
+ hair_grid_interpolate(grid->verts,
+ grid->res,
+ grid->gmin,
+ grid->inv_cellsize,
+ x,
+ &gdensity,
+ gvelocity,
+ gvel_smooth,
+ ggrad,
+ gvelgrad);
+
+ /* velocity according to PIC method (Particle-in-Cell) */
+ copy_v3_v3(v_pic, gvel_smooth);
+
+ /* velocity according to FLIP method (Fluid-Implicit-Particle) */
+ sub_v3_v3v3(v_flip, gvel_smooth, gvelocity);
+ add_v3_v3(v_flip, v);
+
+ interp_v3_v3v3(r_v, v_pic, v_flip, fluid_factor);
}
void BPH_hair_volume_grid_clear(HairGrid *grid)
{
- const int size = hair_grid_size(grid->res);
- int i;
- for (i = 0; i < size; ++i) {
- zero_v3(grid->verts[i].velocity);
- zero_v3(grid->verts[i].velocity_smooth);
- grid->verts[i].density = 0.0f;
- grid->verts[i].samples = 0;
- }
+ const int size = hair_grid_size(grid->res);
+ int i;
+ for (i = 0; i < size; ++i) {
+ zero_v3(grid->verts[i].velocity);
+ zero_v3(grid->verts[i].velocity_smooth);
+ grid->verts[i].density = 0.0f;
+ grid->verts[i].samples = 0;
+ }
}
BLI_INLINE bool hair_grid_point_valid(const float vec[3], float gmin[3], float gmax[3])
{
- return !(vec[0] < gmin[0] || vec[1] < gmin[1] || vec[2] < gmin[2] ||
- vec[0] > gmax[0] || vec[1] > gmax[1] || vec[2] > gmax[2]);
+ return !(vec[0] < gmin[0] || vec[1] < gmin[1] || vec[2] < gmin[2] || vec[0] > gmax[0] ||
+ vec[1] > gmax[1] || vec[2] > gmax[2]);
}
BLI_INLINE float dist_tent_v3f3(const float a[3], float x, float y, float z)
{
- float w = (1.0f - fabsf(a[0] - x)) * (1.0f - fabsf(a[1] - y)) * (1.0f - fabsf(a[2] - z));
- return w;
+ float w = (1.0f - fabsf(a[0] - x)) * (1.0f - fabsf(a[1] - y)) * (1.0f - fabsf(a[2] - z));
+ return w;
}
BLI_INLINE float weights_sum(const float weights[8])
{
- float totweight = 0.0f;
- int i;
- for (i = 0; i < 8; ++i)
- totweight += weights[i];
- return totweight;
+ float totweight = 0.0f;
+ int i;
+ for (i = 0; i < 8; ++i)
+ totweight += weights[i];
+ return totweight;
}
/* returns the grid array offset as well to avoid redundant calculation */
-BLI_INLINE int hair_grid_weights(const int res[3], const float gmin[3], float scale, 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];
-
- 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[1]) * res[0];
-
- 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 );
- weights[2] = dist_tent_v3f3(uvw, (float)i , (float)(j + 1), (float)k );
- weights[3] = dist_tent_v3f3(uvw, (float)(i + 1), (float)(j + 1), (float)k );
- weights[4] = dist_tent_v3f3(uvw, (float)i , (float)j , (float)(k + 1));
- weights[5] = dist_tent_v3f3(uvw, (float)(i + 1), (float)j , (float)(k + 1));
- weights[6] = dist_tent_v3f3(uvw, (float)i , (float)(j + 1), (float)(k + 1));
- weights[7] = dist_tent_v3f3(uvw, (float)(i + 1), (float)(j + 1), (float)(k + 1));
-
-// BLI_assert(fabsf(weights_sum(weights) - 1.0f) < 0.0001f);
-
- return offset;
+ int i, j, k, offset;
+ float uvw[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[1]) * res[0];
+
+ 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);
+ weights[2] = dist_tent_v3f3(uvw, (float)i, (float)(j + 1), (float)k);
+ weights[3] = dist_tent_v3f3(uvw, (float)(i + 1), (float)(j + 1), (float)k);
+ weights[4] = dist_tent_v3f3(uvw, (float)i, (float)j, (float)(k + 1));
+ weights[5] = dist_tent_v3f3(uvw, (float)(i + 1), (float)j, (float)(k + 1));
+ weights[6] = dist_tent_v3f3(uvw, (float)i, (float)(j + 1), (float)(k + 1));
+ weights[7] = dist_tent_v3f3(uvw, (float)(i + 1), (float)(j + 1), (float)(k + 1));
+
+ // BLI_assert(fabsf(weights_sum(weights) - 1.0f) < 0.0001f);
+
+ return offset;
}
BLI_INLINE void grid_to_world(HairGrid *grid, float vecw[3], const float vec[3])
{
- copy_v3_v3(vecw, vec);
- mul_v3_fl(vecw, grid->cellsize);
- add_v3_v3(vecw, grid->gmin);
+ copy_v3_v3(vecw, vec);
+ mul_v3_fl(vecw, grid->cellsize);
+ add_v3_v3(vecw, grid->gmin);
}
void BPH_hair_volume_add_vertex(HairGrid *grid, const float x[3], const float v[3])
{
- const int res[3] = { grid->res[0], grid->res[1], grid->res[2] };
- 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->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[1]) * res[0];
- int iw = di + dj * 2 + dk * 4;
-
- grid->verts[voffset].density += weights[iw];
- madd_v3_v3fl(grid->verts[voffset].velocity, v, weights[iw]);
- }
- }
- }
+ const int res[3] = {grid->res[0], grid->res[1], grid->res[2]};
+ 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->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[1]) * res[0];
+ int iw = di + dj * 2 + dk * 4;
+
+ grid->verts[voffset].density += weights[iw];
+ madd_v3_v3fl(grid->verts[voffset].velocity, v, weights[iw]);
+ }
+ }
+ }
}
#if 0
@@ -340,29 +393,29 @@ BLI_INLINE void hair_volume_eval_grid_vertex(
HairGridVert *vert, const float loc[3], float radius, float dist_scale,
const float x2[3], const float v2[3], const float x3[3], const float v3[3])
{
- float closest[3], lambda, dist, weight;
+ float closest[3], lambda, dist, weight;
- lambda = closest_to_line_v3(closest, loc, x2, x3);
- dist = len_v3v3(closest, loc);
+ lambda = closest_to_line_v3(closest, loc, x2, x3);
+ dist = len_v3v3(closest, loc);
- weight = (radius - dist) * dist_scale;
+ weight = (radius - dist) * dist_scale;
- if (weight > 0.0f) {
- float vel[3];
+ if (weight > 0.0f) {
+ float vel[3];
- interp_v3_v3v3(vel, v2, v3, lambda);
- madd_v3_v3fl(vert->velocity, vel, weight);
- vert->density += weight;
- vert->samples += 1;
- }
+ interp_v3_v3v3(vel, v2, v3, lambda);
+ madd_v3_v3fl(vert->velocity, vel, weight);
+ vert->density += weight;
+ vert->samples += 1;
+ }
}
BLI_INLINE int major_axis_v3(const float v[3])
{
- const float a = fabsf(v[0]);
- const float b = fabsf(v[1]);
- const float c = fabsf(v[2]);
- return a > b ? (a > c ? 0 : 2) : (b > c ? 1 : 2);
+ const float a = fabsf(v[0]);
+ const float b = fabsf(v[1]);
+ const float c = fabsf(v[2]);
+ return a > b ? (a > c ? 0 : 2) : (b > c ? 1 : 2);
}
BLI_INLINE void hair_volume_add_segment_2D(
@@ -374,50 +427,50 @@ BLI_INLINE void hair_volume_add_segment_2D(
HairGridVert *vert, int stride_j, int stride_k, const float loc[3], int axis_j, int axis_k,
int debug_i)
{
- const float radius = 1.5f;
- const float dist_scale = grid->inv_cellsize;
-
- int j, k;
-
- /* boundary checks to be safe */
- CLAMP_MIN(jmin, 0);
- CLAMP_MAX(jmax, resj - 1);
- CLAMP_MIN(kmin, 0);
- CLAMP_MAX(kmax, resk - 1);
-
- HairGridVert *vert_j = vert + jmin * stride_j;
- float loc_j[3] = { loc[0], loc[1], loc[2] };
- loc_j[axis_j] += (float)jmin;
- for (j = jmin; j <= jmax; ++j, vert_j += stride_j, loc_j[axis_j] += 1.0f) {
-
- HairGridVert *vert_k = vert_j + kmin * stride_k;
- float loc_k[3] = { loc_j[0], loc_j[1], loc_j[2] };
- loc_k[axis_k] += (float)kmin;
- for (k = kmin; k <= kmax; ++k, vert_k += stride_k, loc_k[axis_k] += 1.0f) {
-
- hair_volume_eval_grid_vertex(vert_k, loc_k, radius, dist_scale, x2, v2, x3, v3);
-
-#if 0
- {
- float wloc[3], x2w[3], x3w[3];
- grid_to_world(grid, wloc, loc_k);
- grid_to_world(grid, x2w, x2);
- grid_to_world(grid, x3w, x3);
-
- if (vert_k->samples > 0)
- BKE_sim_debug_data_add_circle(wloc, 0.01f, 1.0, 1.0, 0.3, "grid", 2525, debug_i, j, k);
-
- if (grid->debug_value) {
- BKE_sim_debug_data_add_dot(wloc, 1, 0, 0, "grid", 93, debug_i, j, k);
- BKE_sim_debug_data_add_dot(x2w, 0.1, 0.1, 0.7, "grid", 649, debug_i, j, k);
- BKE_sim_debug_data_add_line(wloc, x2w, 0.3, 0.8, 0.3, "grid", 253, debug_i, j, k);
- BKE_sim_debug_data_add_line(wloc, x3w, 0.8, 0.3, 0.3, "grid", 254, debug_i, j, k);
-// BKE_sim_debug_data_add_circle(x2w, len_v3v3(wloc, x2w), 0.2, 0.7, 0.2, "grid", 255, i, j, k);
- }
- }
-#endif
- }
- }
+ const float radius = 1.5f;
+ const float dist_scale = grid->inv_cellsize;
+
+ int j, k;
+
+ /* boundary checks to be safe */
+ CLAMP_MIN(jmin, 0);
+ CLAMP_MAX(jmax, resj - 1);
+ CLAMP_MIN(kmin, 0);
+ CLAMP_MAX(kmax, resk - 1);
+
+ HairGridVert *vert_j = vert + jmin * stride_j;
+ float loc_j[3] = { loc[0], loc[1], loc[2] };
+ loc_j[axis_j] += (float)jmin;
+ for (j = jmin; j <= jmax; ++j, vert_j += stride_j, loc_j[axis_j] += 1.0f) {
+
+ HairGridVert *vert_k = vert_j + kmin * stride_k;
+ float loc_k[3] = { loc_j[0], loc_j[1], loc_j[2] };
+ loc_k[axis_k] += (float)kmin;
+ for (k = kmin; k <= kmax; ++k, vert_k += stride_k, loc_k[axis_k] += 1.0f) {
+
+ hair_volume_eval_grid_vertex(vert_k, loc_k, radius, dist_scale, x2, v2, x3, v3);
+
+# if 0
+ {
+ float wloc[3], x2w[3], x3w[3];
+ grid_to_world(grid, wloc, loc_k);
+ grid_to_world(grid, x2w, x2);
+ grid_to_world(grid, x3w, x3);
+
+ if (vert_k->samples > 0)
+ BKE_sim_debug_data_add_circle(wloc, 0.01f, 1.0, 1.0, 0.3, "grid", 2525, debug_i, j, k);
+
+ if (grid->debug_value) {
+ BKE_sim_debug_data_add_dot(wloc, 1, 0, 0, "grid", 93, debug_i, j, k);
+ BKE_sim_debug_data_add_dot(x2w, 0.1, 0.1, 0.7, "grid", 649, debug_i, j, k);
+ BKE_sim_debug_data_add_line(wloc, x2w, 0.3, 0.8, 0.3, "grid", 253, debug_i, j, k);
+ BKE_sim_debug_data_add_line(wloc, x3w, 0.8, 0.3, 0.3, "grid", 254, debug_i, j, k);
+// BKE_sim_debug_data_add_circle(x2w, len_v3v3(wloc, x2w), 0.2, 0.7, 0.2, "grid", 255, i, j, k);
+ }
+ }
+# endif
+ }
+ }
}
/* Uses a variation of Bresenham's algorithm for rasterizing a 3D grid with a line segment.
@@ -431,191 +484,207 @@ void BPH_hair_volume_add_segment(
const float x3[3], const float v3[3], const float x4[3], const float v4[3],
const float dir1[3], const float dir2[3], const float dir3[3])
{
- 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);
- const int axis1 = (axis0 + 1) % 3;
- const int axis2 = (axis0 + 2) % 3;
-
- /* vertex buffer offset factors along cardinal axes */
- const int strides[3] = { 1, res[0], res[0] * res[1] };
- const int stride0 = strides[axis0];
- const int stride1 = strides[axis1];
- const int stride2 = strides[axis2];
-
- /* increment of secondary directions per step in the primary direction
- * note: we always go in the positive direction along axis0, so the sign can be inverted
- */
- const float inc1 = dir2[axis1] / dir2[axis0];
- const float inc2 = dir2[axis2] / dir2[axis0];
-
- /* start/end points, so increment along axis0 is always positive */
- const float *start = x2[axis0] < x3[axis0] ? x2 : x3;
- const float *end = x2[axis0] < x3[axis0] ? x3 : x2;
- const float start0 = start[axis0], start1 = start[axis1], start2 = start[axis2];
- const float end0 = end[axis0];
-
- /* range along primary direction */
- const int imin = max_ii(floor_int(start[axis0]) - 1, 0);
- const int imax = min_ii(floor_int(end[axis0]) + 2, res[axis0] - 1);
-
- float h = 0.0f;
- HairGridVert *vert0;
- float loc0[3];
- int j0, k0, j0_prev, k0_prev;
- int i;
-
- for (i = imin; i <= imax; ++i) {
- float shift1, shift2; /* fraction of a full cell shift [0.0, 1.0) */
- int jmin, jmax, kmin, kmax;
-
- h = CLAMPIS((float)i, start0, end0);
-
- shift1 = start1 + (h - start0) * inc1;
- shift2 = start2 + (h - start0) * inc2;
-
- j0_prev = j0;
- j0 = floor_int(shift1);
-
- k0_prev = k0;
- k0 = floor_int(shift2);
-
- if (i > imin) {
- jmin = min_ii(j0, j0_prev);
- jmax = max_ii(j0, j0_prev);
- kmin = min_ii(k0, k0_prev);
- kmax = max_ii(k0, k0_prev);
- }
- else {
- jmin = jmax = j0;
- kmin = kmax = k0;
- }
-
- vert0 = grid->verts + i * stride0;
- loc0[axis0] = (float)i;
- loc0[axis1] = 0.0f;
- loc0[axis2] = 0.0f;
-
- hair_volume_add_segment_2D(
- grid, x1, v1, x2, v2, x3, v3, x4, v4, dir1, dir2, dir3,
- res[axis1], res[axis2], jmin - 1, jmax + 2, kmin - 1, kmax + 2,
- vert0, stride1, stride2, loc0, axis1, axis2,
- i);
- }
+ 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);
+ const int axis1 = (axis0 + 1) % 3;
+ const int axis2 = (axis0 + 2) % 3;
+
+ /* vertex buffer offset factors along cardinal axes */
+ const int strides[3] = { 1, res[0], res[0] * res[1] };
+ const int stride0 = strides[axis0];
+ const int stride1 = strides[axis1];
+ const int stride2 = strides[axis2];
+
+ /* increment of secondary directions per step in the primary direction
+ * note: we always go in the positive direction along axis0, so the sign can be inverted
+ */
+ const float inc1 = dir2[axis1] / dir2[axis0];
+ const float inc2 = dir2[axis2] / dir2[axis0];
+
+ /* start/end points, so increment along axis0 is always positive */
+ const float *start = x2[axis0] < x3[axis0] ? x2 : x3;
+ const float *end = x2[axis0] < x3[axis0] ? x3 : x2;
+ const float start0 = start[axis0], start1 = start[axis1], start2 = start[axis2];
+ const float end0 = end[axis0];
+
+ /* range along primary direction */
+ const int imin = max_ii(floor_int(start[axis0]) - 1, 0);
+ const int imax = min_ii(floor_int(end[axis0]) + 2, res[axis0] - 1);
+
+ float h = 0.0f;
+ HairGridVert *vert0;
+ float loc0[3];
+ int j0, k0, j0_prev, k0_prev;
+ int i;
+
+ for (i = imin; i <= imax; ++i) {
+ float shift1, shift2; /* fraction of a full cell shift [0.0, 1.0) */
+ int jmin, jmax, kmin, kmax;
+
+ h = CLAMPIS((float)i, start0, end0);
+
+ shift1 = start1 + (h - start0) * inc1;
+ shift2 = start2 + (h - start0) * inc2;
+
+ j0_prev = j0;
+ j0 = floor_int(shift1);
+
+ k0_prev = k0;
+ k0 = floor_int(shift2);
+
+ if (i > imin) {
+ jmin = min_ii(j0, j0_prev);
+ jmax = max_ii(j0, j0_prev);
+ kmin = min_ii(k0, k0_prev);
+ kmax = max_ii(k0, k0_prev);
+ }
+ else {
+ jmin = jmax = j0;
+ kmin = kmax = k0;
+ }
+
+ vert0 = grid->verts + i * stride0;
+ loc0[axis0] = (float)i;
+ loc0[axis1] = 0.0f;
+ loc0[axis2] = 0.0f;
+
+ hair_volume_add_segment_2D(
+ grid, x1, v1, x2, v2, x3, v3, x4, v4, dir1, dir2, dir3,
+ res[axis1], res[axis2], jmin - 1, jmax + 2, kmin - 1, kmax + 2,
+ vert0, stride1, stride2, loc0, axis1, axis2,
+ i);
+ }
}
#else
-BLI_INLINE void hair_volume_eval_grid_vertex_sample(
- HairGridVert *vert, const float loc[3], float radius, float dist_scale,
- const float x[3], const float v[3])
+BLI_INLINE void hair_volume_eval_grid_vertex_sample(HairGridVert *vert,
+ const float loc[3],
+ float radius,
+ float dist_scale,
+ const float x[3],
+ const float v[3])
{
- float dist, weight;
+ float dist, weight;
- dist = len_v3v3(x, loc);
+ dist = len_v3v3(x, loc);
- weight = (radius - dist) * dist_scale;
+ weight = (radius - dist) * dist_scale;
- if (weight > 0.0f) {
- madd_v3_v3fl(vert->velocity, v, weight);
- vert->density += weight;
- vert->samples += 1;
- }
+ if (weight > 0.0f) {
+ madd_v3_v3fl(vert->velocity, v, weight);
+ vert->density += weight;
+ vert->samples += 1;
+ }
}
/* XXX simplified test implementation using a series of discrete sample along the segment,
* instead of finding the closest point for all affected grid vertices.
*/
-void BPH_hair_volume_add_segment(
- HairGrid *grid,
- const float UNUSED(x1[3]), const float UNUSED(v1[3]), const float x2[3], const float v2[3],
- const float x3[3], const float v3[3], const float UNUSED(x4[3]), const float UNUSED(v4[3]),
- const float UNUSED(dir1[3]), const float UNUSED(dir2[3]), const float UNUSED(dir3[3]))
+void BPH_hair_volume_add_segment(HairGrid *grid,
+ const float UNUSED(x1[3]),
+ const float UNUSED(v1[3]),
+ const float x2[3],
+ const float v2[3],
+ const float x3[3],
+ const float v3[3],
+ const float UNUSED(x4[3]),
+ const float UNUSED(v4[3]),
+ const float UNUSED(dir1[3]),
+ const float UNUSED(dir2[3]),
+ const float UNUSED(dir3[3]))
{
- const float radius = 1.5f;
- const float dist_scale = grid->inv_cellsize;
-
- const int res[3] = { grid->res[0], grid->res[1], grid->res[2] };
- const int stride[3] = { 1, res[0], res[0] * res[1] };
- const int num_samples = 10;
-
- int s;
-
- for (s = 0; s < num_samples; ++s) {
- float x[3], v[3];
- int i, j, k;
-
- float f = (float)s / (float)(num_samples - 1);
- interp_v3_v3v3(x, x2, x3, f);
- interp_v3_v3v3(v, v2, v3, f);
-
- int imin = max_ii(floor_int(x[0]) - 2, 0);
- int imax = min_ii(floor_int(x[0]) + 2, res[0] - 1);
- int jmin = max_ii(floor_int(x[1]) - 2, 0);
- int jmax = min_ii(floor_int(x[1]) + 2, res[1] - 1);
- int kmin = max_ii(floor_int(x[2]) - 2, 0);
- int kmax = min_ii(floor_int(x[2]) + 2, res[2] - 1);
-
- for (k = kmin; k <= kmax; ++k) {
- for (j = jmin; j <= jmax; ++j) {
- for (i = imin; i <= imax; ++i) {
- float loc[3] = { (float)i, (float)j, (float)k };
- HairGridVert *vert = grid->verts + i * stride[0] + j * stride[1] + k * stride[2];
-
- hair_volume_eval_grid_vertex_sample(vert, loc, radius, dist_scale, x, v);
- }
- }
- }
- }
+ const float radius = 1.5f;
+ const float dist_scale = grid->inv_cellsize;
+
+ const int res[3] = {grid->res[0], grid->res[1], grid->res[2]};
+ const int stride[3] = {1, res[0], res[0] * res[1]};
+ const int num_samples = 10;
+
+ int s;
+
+ for (s = 0; s < num_samples; ++s) {
+ float x[3], v[3];
+ int i, j, k;
+
+ float f = (float)s / (float)(num_samples - 1);
+ interp_v3_v3v3(x, x2, x3, f);
+ interp_v3_v3v3(v, v2, v3, f);
+
+ int imin = max_ii(floor_int(x[0]) - 2, 0);
+ int imax = min_ii(floor_int(x[0]) + 2, res[0] - 1);
+ int jmin = max_ii(floor_int(x[1]) - 2, 0);
+ int jmax = min_ii(floor_int(x[1]) + 2, res[1] - 1);
+ int kmin = max_ii(floor_int(x[2]) - 2, 0);
+ int kmax = min_ii(floor_int(x[2]) + 2, res[2] - 1);
+
+ for (k = kmin; k <= kmax; ++k) {
+ for (j = jmin; j <= jmax; ++j) {
+ for (i = imin; i <= imax; ++i) {
+ float loc[3] = {(float)i, (float)j, (float)k};
+ HairGridVert *vert = grid->verts + i * stride[0] + j * stride[1] + k * stride[2];
+
+ hair_volume_eval_grid_vertex_sample(vert, loc, radius, dist_scale, x, v);
+ }
+ }
+ }
+ }
}
#endif
void BPH_hair_volume_normalize_vertex_grid(HairGrid *grid)
{
- int i, size = hair_grid_size(grid->res);
- /* divide velocity with density */
- for (i = 0; i < size; i++) {
- float density = grid->verts[i].density;
- if (density > 0.0f)
- mul_v3_fl(grid->verts[i].velocity, 1.0f / density);
- }
+ int i, size = hair_grid_size(grid->res);
+ /* divide velocity with density */
+ for (i = 0; i < size; i++) {
+ float density = grid->verts[i].density;
+ if (density > 0.0f)
+ mul_v3_fl(grid->verts[i].velocity, 1.0f / density);
+ }
}
-static const float density_threshold = 0.001f; /* cells with density below this are considered empty */
+static const float density_threshold =
+ 0.001f; /* cells with density below this are considered empty */
/* Contribution of target density pressure to the laplacian in the pressure poisson equation.
* This is based on the model found in
* "Two-way Coupled SPH and Particle Level Set Fluid Simulation" (Losasso et al., 2008)
*/
-BLI_INLINE float hair_volume_density_divergence(float density, float target_density, float strength)
+BLI_INLINE float hair_volume_density_divergence(float density,
+ float target_density,
+ float strength)
{
- if (density > density_threshold && density > target_density)
- return strength * logf(target_density / density);
- else
- return 0.0f;
+ if (density > density_threshold && density > target_density)
+ return strength * logf(target_density / density);
+ else
+ return 0.0f;
}
-bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target_density, float target_strength)
+bool BPH_hair_volume_solve_divergence(HairGrid *grid,
+ float /*dt*/,
+ float target_density,
+ float target_strength)
{
- const float flowfac = grid->cellsize;
- const float inv_flowfac = 1.0f / grid->cellsize;
+ const float flowfac = grid->cellsize;
+ const float inv_flowfac = 1.0f / grid->cellsize;
- /*const int num_cells = hair_grid_size(grid->res);*/
- const int res[3] = { grid->res[0], grid->res[1], grid->res[2] };
- const int resA[3] = { grid->res[0] + 2, grid->res[1] + 2, grid->res[2] + 2 };
+ /*const int num_cells = hair_grid_size(grid->res);*/
+ const int res[3] = {grid->res[0], grid->res[1], grid->res[2]};
+ const int resA[3] = {grid->res[0] + 2, grid->res[1] + 2, grid->res[2] + 2};
- const int stride0 = 1;
- const int stride1 = grid->res[0];
- const int stride2 = grid->res[1] * grid->res[0];
- const int strideA0 = 1;
- const int strideA1 = grid->res[0] + 2;
- const int strideA2 = (grid->res[1] + 2) * (grid->res[0] + 2);
+ const int stride0 = 1;
+ const int stride1 = grid->res[0];
+ const int stride2 = grid->res[1] * grid->res[0];
+ const int strideA0 = 1;
+ const int strideA1 = grid->res[0] + 2;
+ const int strideA2 = (grid->res[1] + 2) * (grid->res[0] + 2);
- const int num_cells = res[0] * res[1] * res[2];
- const int num_cellsA = (res[0] + 2) * (res[1] + 2) * (res[2] + 2);
+ const int num_cells = res[0] * res[1] * res[2];
+ const int num_cellsA = (res[0] + 2) * (res[1] + 2) * (res[2] + 2);
- HairGridVert *vert_start = grid->verts - (stride0 + stride1 + stride2);
- HairGridVert *vert;
- int i, j, k;
+ HairGridVert *vert_start = grid->verts - (stride0 + stride1 + stride2);
+ HairGridVert *vert;
+ int i, j, k;
#define MARGIN_i0 (i < 1)
#define MARGIN_j0 (j < 1)
@@ -631,259 +700,263 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
#define NEIGHBOR_MARGIN_j1 (j >= resA[1] - 2)
#define NEIGHBOR_MARGIN_k1 (k >= resA[2] - 2)
- BLI_assert(num_cells >= 1);
-
- /* Calculate divergence */
- lVector B(num_cellsA);
- for (k = 0; k < resA[2]; ++k) {
- for (j = 0; j < resA[1]; ++j) {
- for (i = 0; i < resA[0]; ++i) {
- int u = i * strideA0 + j * strideA1 + k * strideA2;
- bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 || MARGIN_k1;
-
- if (is_margin) {
- B[u] = 0.0f;
- continue;
- }
-
- vert = vert_start + i * stride0 + j * stride1 + k * stride2;
-
- const float *v0 = vert->velocity;
- float dx = 0.0f, dy = 0.0f, dz = 0.0f;
- if (!NEIGHBOR_MARGIN_i0)
- dx += v0[0] - (vert - stride0)->velocity[0];
- if (!NEIGHBOR_MARGIN_i1)
- dx += (vert + stride0)->velocity[0] - v0[0];
- if (!NEIGHBOR_MARGIN_j0)
- dy += v0[1] - (vert - stride1)->velocity[1];
- if (!NEIGHBOR_MARGIN_j1)
- dy += (vert + stride1)->velocity[1] - v0[1];
- if (!NEIGHBOR_MARGIN_k0)
- dz += v0[2] - (vert - stride2)->velocity[2];
- if (!NEIGHBOR_MARGIN_k1)
- dz += (vert + stride2)->velocity[2] - v0[2];
-
- float divergence = -0.5f * flowfac * (dx + dy + dz);
-
- /* adjustment term for target density */
- float target = hair_volume_density_divergence(vert->density, target_density, target_strength);
-
- /* B vector contains the finite difference approximation of the velocity divergence.
- * Note: according to the discretized Navier-Stokes equation the rhs vector
- * and resulting pressure gradient should be multiplied by the (inverse) density;
- * however, this is already included in the weighting of hair velocities on the grid!
- */
- B[u] = divergence - target;
+ BLI_assert(num_cells >= 1);
+
+ /* Calculate divergence */
+ lVector B(num_cellsA);
+ for (k = 0; k < resA[2]; ++k) {
+ for (j = 0; j < resA[1]; ++j) {
+ for (i = 0; i < resA[0]; ++i) {
+ int u = i * strideA0 + j * strideA1 + k * strideA2;
+ bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 ||
+ MARGIN_k1;
+
+ if (is_margin) {
+ B[u] = 0.0f;
+ continue;
+ }
+
+ vert = vert_start + i * stride0 + j * stride1 + k * stride2;
+
+ const float *v0 = vert->velocity;
+ float dx = 0.0f, dy = 0.0f, dz = 0.0f;
+ if (!NEIGHBOR_MARGIN_i0)
+ dx += v0[0] - (vert - stride0)->velocity[0];
+ if (!NEIGHBOR_MARGIN_i1)
+ dx += (vert + stride0)->velocity[0] - v0[0];
+ if (!NEIGHBOR_MARGIN_j0)
+ dy += v0[1] - (vert - stride1)->velocity[1];
+ if (!NEIGHBOR_MARGIN_j1)
+ dy += (vert + stride1)->velocity[1] - v0[1];
+ if (!NEIGHBOR_MARGIN_k0)
+ dz += v0[2] - (vert - stride2)->velocity[2];
+ if (!NEIGHBOR_MARGIN_k1)
+ dz += (vert + stride2)->velocity[2] - v0[2];
+
+ float divergence = -0.5f * flowfac * (dx + dy + dz);
+
+ /* adjustment term for target density */
+ float target = hair_volume_density_divergence(
+ vert->density, target_density, target_strength);
+
+ /* B vector contains the finite difference approximation of the velocity divergence.
+ * Note: according to the discretized Navier-Stokes equation the rhs vector
+ * and resulting pressure gradient should be multiplied by the (inverse) density;
+ * however, this is already included in the weighting of hair velocities on the grid!
+ */
+ B[u] = divergence - target;
#if 0
- {
- float wloc[3], loc[3];
- float col0[3] = {0.0, 0.0, 0.0};
- float colp[3] = {0.0, 1.0, 1.0};
- float coln[3] = {1.0, 0.0, 1.0};
- float col[3];
- float fac;
-
- loc[0] = (float)(i - 1);
- loc[1] = (float)(j - 1);
- loc[2] = (float)(k - 1);
- grid_to_world(grid, wloc, loc);
-
- if (divergence > 0.0f) {
- fac = CLAMPIS(divergence * target_strength, 0.0, 1.0);
- interp_v3_v3v3(col, col0, colp, fac);
- }
- else {
- fac = CLAMPIS(-divergence * target_strength, 0.0, 1.0);
- interp_v3_v3v3(col, col0, coln, fac);
- }
- if (fac > 0.05f)
- BKE_sim_debug_data_add_circle(grid->debug_data, wloc, 0.01f, col[0], col[1], col[2], "grid", 5522, i, j, k);
- }
+ {
+ float wloc[3], loc[3];
+ float col0[3] = {0.0, 0.0, 0.0};
+ float colp[3] = {0.0, 1.0, 1.0};
+ float coln[3] = {1.0, 0.0, 1.0};
+ float col[3];
+ float fac;
+
+ loc[0] = (float)(i - 1);
+ loc[1] = (float)(j - 1);
+ loc[2] = (float)(k - 1);
+ grid_to_world(grid, wloc, loc);
+
+ if (divergence > 0.0f) {
+ fac = CLAMPIS(divergence * target_strength, 0.0, 1.0);
+ interp_v3_v3v3(col, col0, colp, fac);
+ }
+ else {
+ fac = CLAMPIS(-divergence * target_strength, 0.0, 1.0);
+ interp_v3_v3v3(col, col0, coln, fac);
+ }
+ if (fac > 0.05f)
+ BKE_sim_debug_data_add_circle(grid->debug_data, wloc, 0.01f, col[0], col[1], col[2], "grid", 5522, i, j, k);
+ }
#endif
- }
- }
- }
-
- /* Main Poisson equation system:
- * This is derived from the discretezation of the Poisson equation
- * div(grad(p)) = div(v)
- *
- * The finite difference approximation yields the linear equation system described here:
- * https://en.wikipedia.org/wiki/Discrete_Poisson_equation
- */
- lMatrix A(num_cellsA, num_cellsA);
- /* Reserve space for the base equation system (without boundary conditions).
- * Each column contains a factor 6 on the diagonal
- * and up to 6 factors -1 on other places.
- */
- A.reserve(Eigen::VectorXi::Constant(num_cellsA, 7));
-
- for (k = 0; k < resA[2]; ++k) {
- for (j = 0; j < resA[1]; ++j) {
- for (i = 0; i < resA[0]; ++i) {
- int u = i * strideA0 + j * strideA1 + k * strideA2;
- bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 || MARGIN_k1;
-
- vert = vert_start + i * stride0 + j * stride1 + k * stride2;
- if (!is_margin && vert->density > density_threshold) {
- int neighbors_lo = 0;
- int neighbors_hi = 0;
- int non_solid_neighbors = 0;
- int neighbor_lo_index[3];
- int neighbor_hi_index[3];
- int n;
-
- /* check for upper bounds in advance
- * to get the correct number of neighbors,
- * needed for the diagonal element
- */
- if (!NEIGHBOR_MARGIN_k0 && (vert - stride2)->density > density_threshold)
- neighbor_lo_index[neighbors_lo++] = u - strideA2;
- if (!NEIGHBOR_MARGIN_j0 && (vert - stride1)->density > density_threshold)
- neighbor_lo_index[neighbors_lo++] = u - strideA1;
- if (!NEIGHBOR_MARGIN_i0 && (vert - stride0)->density > density_threshold)
- neighbor_lo_index[neighbors_lo++] = u - strideA0;
- if (!NEIGHBOR_MARGIN_i1 && (vert + stride0)->density > density_threshold)
- neighbor_hi_index[neighbors_hi++] = u + strideA0;
- if (!NEIGHBOR_MARGIN_j1 && (vert + stride1)->density > density_threshold)
- neighbor_hi_index[neighbors_hi++] = u + strideA1;
- if (!NEIGHBOR_MARGIN_k1 && (vert + stride2)->density > density_threshold)
- neighbor_hi_index[neighbors_hi++] = u + strideA2;
-
- /*int liquid_neighbors = neighbors_lo + neighbors_hi;*/
- non_solid_neighbors = 6;
-
- for (n = 0; n < neighbors_lo; ++n)
- A.insert(neighbor_lo_index[n], u) = -1.0f;
- A.insert(u, u) = (float)non_solid_neighbors;
- for (n = 0; n < neighbors_hi; ++n)
- A.insert(neighbor_hi_index[n], u) = -1.0f;
- }
- else {
- A.insert(u, u) = 1.0f;
- }
- }
- }
- }
-
- ConjugateGradient cg;
- cg.setMaxIterations(100);
- cg.setTolerance(0.01f);
-
- cg.compute(A);
-
- lVector p = cg.solve(B);
-
- if (cg.info() == Eigen::Success) {
- /* Calculate velocity = grad(p) */
- for (k = 0; k < resA[2]; ++k) {
- for (j = 0; j < resA[1]; ++j) {
- for (i = 0; i < resA[0]; ++i) {
- int u = i * strideA0 + j * strideA1 + k * strideA2;
- bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 || MARGIN_k1;
- if (is_margin)
- continue;
-
- vert = vert_start + i * stride0 + j * stride1 + k * stride2;
- if (vert->density > density_threshold) {
- float p_left = p[u - strideA0];
- float p_right = p[u + strideA0];
- float p_down = p[u - strideA1];
- float p_up = p[u + strideA1];
- float p_bottom = p[u - strideA2];
- float p_top = p[u + strideA2];
-
- /* finite difference estimate of pressure gradient */
- float dvel[3];
- dvel[0] = p_right - p_left;
- dvel[1] = p_up - p_down;
- dvel[2] = p_top - p_bottom;
- mul_v3_fl(dvel, -0.5f * inv_flowfac);
-
- /* pressure gradient describes velocity delta */
- add_v3_v3v3(vert->velocity_smooth, vert->velocity, dvel);
- }
- else {
- zero_v3(vert->velocity_smooth);
- }
- }
- }
- }
+ }
+ }
+ }
+
+ /* Main Poisson equation system:
+ * This is derived from the discretezation of the Poisson equation
+ * div(grad(p)) = div(v)
+ *
+ * The finite difference approximation yields the linear equation system described here:
+ * https://en.wikipedia.org/wiki/Discrete_Poisson_equation
+ */
+ lMatrix A(num_cellsA, num_cellsA);
+ /* Reserve space for the base equation system (without boundary conditions).
+ * Each column contains a factor 6 on the diagonal
+ * and up to 6 factors -1 on other places.
+ */
+ A.reserve(Eigen::VectorXi::Constant(num_cellsA, 7));
+
+ for (k = 0; k < resA[2]; ++k) {
+ for (j = 0; j < resA[1]; ++j) {
+ for (i = 0; i < resA[0]; ++i) {
+ int u = i * strideA0 + j * strideA1 + k * strideA2;
+ bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 ||
+ MARGIN_k1;
+
+ vert = vert_start + i * stride0 + j * stride1 + k * stride2;
+ if (!is_margin && vert->density > density_threshold) {
+ int neighbors_lo = 0;
+ int neighbors_hi = 0;
+ int non_solid_neighbors = 0;
+ int neighbor_lo_index[3];
+ int neighbor_hi_index[3];
+ int n;
+
+ /* check for upper bounds in advance
+ * to get the correct number of neighbors,
+ * needed for the diagonal element
+ */
+ if (!NEIGHBOR_MARGIN_k0 && (vert - stride2)->density > density_threshold)
+ neighbor_lo_index[neighbors_lo++] = u - strideA2;
+ if (!NEIGHBOR_MARGIN_j0 && (vert - stride1)->density > density_threshold)
+ neighbor_lo_index[neighbors_lo++] = u - strideA1;
+ if (!NEIGHBOR_MARGIN_i0 && (vert - stride0)->density > density_threshold)
+ neighbor_lo_index[neighbors_lo++] = u - strideA0;
+ if (!NEIGHBOR_MARGIN_i1 && (vert + stride0)->density > density_threshold)
+ neighbor_hi_index[neighbors_hi++] = u + strideA0;
+ if (!NEIGHBOR_MARGIN_j1 && (vert + stride1)->density > density_threshold)
+ neighbor_hi_index[neighbors_hi++] = u + strideA1;
+ if (!NEIGHBOR_MARGIN_k1 && (vert + stride2)->density > density_threshold)
+ neighbor_hi_index[neighbors_hi++] = u + strideA2;
+
+ /*int liquid_neighbors = neighbors_lo + neighbors_hi;*/
+ non_solid_neighbors = 6;
+
+ for (n = 0; n < neighbors_lo; ++n)
+ A.insert(neighbor_lo_index[n], u) = -1.0f;
+ A.insert(u, u) = (float)non_solid_neighbors;
+ for (n = 0; n < neighbors_hi; ++n)
+ A.insert(neighbor_hi_index[n], u) = -1.0f;
+ }
+ else {
+ A.insert(u, u) = 1.0f;
+ }
+ }
+ }
+ }
+
+ ConjugateGradient cg;
+ cg.setMaxIterations(100);
+ cg.setTolerance(0.01f);
+
+ cg.compute(A);
+
+ lVector p = cg.solve(B);
+
+ if (cg.info() == Eigen::Success) {
+ /* Calculate velocity = grad(p) */
+ for (k = 0; k < resA[2]; ++k) {
+ for (j = 0; j < resA[1]; ++j) {
+ for (i = 0; i < resA[0]; ++i) {
+ int u = i * strideA0 + j * strideA1 + k * strideA2;
+ bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 ||
+ MARGIN_k1;
+ if (is_margin)
+ continue;
+
+ vert = vert_start + i * stride0 + j * stride1 + k * stride2;
+ if (vert->density > density_threshold) {
+ float p_left = p[u - strideA0];
+ float p_right = p[u + strideA0];
+ float p_down = p[u - strideA1];
+ float p_up = p[u + strideA1];
+ float p_bottom = p[u - strideA2];
+ float p_top = p[u + strideA2];
+
+ /* finite difference estimate of pressure gradient */
+ float dvel[3];
+ dvel[0] = p_right - p_left;
+ dvel[1] = p_up - p_down;
+ dvel[2] = p_top - p_bottom;
+ mul_v3_fl(dvel, -0.5f * inv_flowfac);
+
+ /* pressure gradient describes velocity delta */
+ add_v3_v3v3(vert->velocity_smooth, vert->velocity, dvel);
+ }
+ else {
+ zero_v3(vert->velocity_smooth);
+ }
+ }
+ }
+ }
#if 0
- {
- int axis = 0;
- float offset = 0.0f;
-
- int slice = (offset - grid->gmin[axis]) / grid->cellsize;
-
- for (k = 0; k < resA[2]; ++k) {
- for (j = 0; j < resA[1]; ++j) {
- for (i = 0; i < resA[0]; ++i) {
- int u = i * strideA0 + j * strideA1 + k * strideA2;
- bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 || MARGIN_k1;
- if (i != slice)
- continue;
-
- vert = vert_start + i * stride0 + j * stride1 + k * stride2;
-
- float wloc[3], loc[3];
- float col0[3] = {0.0, 0.0, 0.0};
- float colp[3] = {0.0, 1.0, 1.0};
- float coln[3] = {1.0, 0.0, 1.0};
- float col[3];
- float fac;
-
- loc[0] = (float)(i - 1);
- loc[1] = (float)(j - 1);
- loc[2] = (float)(k - 1);
- grid_to_world(grid, wloc, loc);
-
- float pressure = p[u];
- if (pressure > 0.0f) {
- fac = CLAMPIS(pressure * grid->debug1, 0.0, 1.0);
- interp_v3_v3v3(col, col0, colp, fac);
- }
- else {
- fac = CLAMPIS(-pressure * grid->debug1, 0.0, 1.0);
- interp_v3_v3v3(col, col0, coln, fac);
- }
- if (fac > 0.05f)
- BKE_sim_debug_data_add_circle(grid->debug_data, wloc, 0.01f, col[0], col[1], col[2], "grid", 5533, i, j, k);
-
- if (!is_margin) {
- float dvel[3];
- sub_v3_v3v3(dvel, vert->velocity_smooth, vert->velocity);
-// BKE_sim_debug_data_add_vector(grid->debug_data, wloc, dvel, 1, 1, 1, "grid", 5566, i, j, k);
- }
-
- if (!is_margin) {
- float d = CLAMPIS(vert->density * grid->debug2, 0.0f, 1.0f);
- float col0[3] = {0.3, 0.3, 0.3};
- float colp[3] = {0.0, 0.0, 1.0};
- float col[3];
-
- interp_v3_v3v3(col, col0, colp, d);
-// if (d > 0.05f)
-// BKE_sim_debug_data_add_dot(grid->debug_data, wloc, col[0], col[1], col[2], "grid", 5544, i, j, k);
- }
- }
- }
- }
- }
+ {
+ int axis = 0;
+ float offset = 0.0f;
+
+ int slice = (offset - grid->gmin[axis]) / grid->cellsize;
+
+ for (k = 0; k < resA[2]; ++k) {
+ for (j = 0; j < resA[1]; ++j) {
+ for (i = 0; i < resA[0]; ++i) {
+ int u = i * strideA0 + j * strideA1 + k * strideA2;
+ bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 || MARGIN_k1;
+ if (i != slice)
+ continue;
+
+ vert = vert_start + i * stride0 + j * stride1 + k * stride2;
+
+ float wloc[3], loc[3];
+ float col0[3] = {0.0, 0.0, 0.0};
+ float colp[3] = {0.0, 1.0, 1.0};
+ float coln[3] = {1.0, 0.0, 1.0};
+ float col[3];
+ float fac;
+
+ loc[0] = (float)(i - 1);
+ loc[1] = (float)(j - 1);
+ loc[2] = (float)(k - 1);
+ grid_to_world(grid, wloc, loc);
+
+ float pressure = p[u];
+ if (pressure > 0.0f) {
+ fac = CLAMPIS(pressure * grid->debug1, 0.0, 1.0);
+ interp_v3_v3v3(col, col0, colp, fac);
+ }
+ else {
+ fac = CLAMPIS(-pressure * grid->debug1, 0.0, 1.0);
+ interp_v3_v3v3(col, col0, coln, fac);
+ }
+ if (fac > 0.05f)
+ BKE_sim_debug_data_add_circle(grid->debug_data, wloc, 0.01f, col[0], col[1], col[2], "grid", 5533, i, j, k);
+
+ if (!is_margin) {
+ float dvel[3];
+ sub_v3_v3v3(dvel, vert->velocity_smooth, vert->velocity);
+// BKE_sim_debug_data_add_vector(grid->debug_data, wloc, dvel, 1, 1, 1, "grid", 5566, i, j, k);
+ }
+
+ if (!is_margin) {
+ float d = CLAMPIS(vert->density * grid->debug2, 0.0f, 1.0f);
+ float col0[3] = {0.3, 0.3, 0.3};
+ float colp[3] = {0.0, 0.0, 1.0};
+ float col[3];
+
+ interp_v3_v3v3(col, col0, colp, d);
+// if (d > 0.05f)
+// BKE_sim_debug_data_add_dot(grid->debug_data, wloc, col[0], col[1], col[2], "grid", 5544, i, j, k);
+ }
+ }
+ }
+ }
+ }
#endif
- return true;
- }
- else {
- /* Clear result in case of error */
- for (i = 0, vert = grid->verts; i < num_cells; ++i, ++vert) {
- zero_v3(vert->velocity_smooth);
- }
+ return true;
+ }
+ else {
+ /* Clear result in case of error */
+ for (i = 0, vert = grid->verts; i < num_cells; ++i, ++vert) {
+ zero_v3(vert->velocity_smooth);
+ }
- return false;
- }
+ return false;
+ }
}
#if 0 /* XXX weighting is incorrect, disabled for now */
@@ -893,209 +966,216 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
BLI_INLINE void hair_volume_filter_box_convolute(HairVertexGrid *grid, float invD, const int kernel_size[3], int i, int j, int k)
{
- int res = grid->res;
- int p, q, r;
- int minp = max_ii(i - kernel_size[0], 0), maxp = min_ii(i + kernel_size[0], res - 1);
- int minq = max_ii(j - kernel_size[1], 0), maxq = min_ii(j + kernel_size[1], res - 1);
- int minr = max_ii(k - kernel_size[2], 0), maxr = min_ii(k + kernel_size[2], res - 1);
- int offset, kernel_offset, kernel_dq, kernel_dr;
- HairGridVert *verts;
- float *vel_smooth;
-
- offset = i + (j + k * res) * res;
- verts = grid->verts;
- vel_smooth = verts[offset].velocity_smooth;
-
- kernel_offset = minp + (minq + minr * res) * res;
- kernel_dq = res;
- kernel_dr = res * res;
- for (r = minr; r <= maxr; ++r) {
- for (q = minq; q <= maxq; ++q) {
- for (p = minp; p <= maxp; ++p) {
-
- madd_v3_v3fl(vel_smooth, verts[kernel_offset].velocity, invD);
-
- kernel_offset += 1;
- }
- kernel_offset += kernel_dq;
- }
- kernel_offset += kernel_dr;
- }
+ int res = grid->res;
+ int p, q, r;
+ int minp = max_ii(i - kernel_size[0], 0), maxp = min_ii(i + kernel_size[0], res - 1);
+ int minq = max_ii(j - kernel_size[1], 0), maxq = min_ii(j + kernel_size[1], res - 1);
+ int minr = max_ii(k - kernel_size[2], 0), maxr = min_ii(k + kernel_size[2], res - 1);
+ int offset, kernel_offset, kernel_dq, kernel_dr;
+ HairGridVert *verts;
+ float *vel_smooth;
+
+ offset = i + (j + k * res) * res;
+ verts = grid->verts;
+ vel_smooth = verts[offset].velocity_smooth;
+
+ kernel_offset = minp + (minq + minr * res) * res;
+ kernel_dq = res;
+ kernel_dr = res * res;
+ for (r = minr; r <= maxr; ++r) {
+ for (q = minq; q <= maxq; ++q) {
+ for (p = minp; p <= maxp; ++p) {
+
+ madd_v3_v3fl(vel_smooth, verts[kernel_offset].velocity, invD);
+
+ kernel_offset += 1;
+ }
+ kernel_offset += kernel_dq;
+ }
+ kernel_offset += kernel_dr;
+ }
}
void BPH_hair_volume_vertex_grid_filter_box(HairVertexGrid *grid, int kernel_size)
{
- int size = hair_grid_size(grid->res);
- int kernel_sizev[3] = {kernel_size, kernel_size, kernel_size};
- int tot;
- float invD;
- int i, j, k;
-
- if (kernel_size <= 0)
- return;
-
- tot = kernel_size * 2 + 1;
- invD = 1.0f / (float)(tot * tot * tot);
-
- /* clear values for convolution */
- for (i = 0; i < size; ++i) {
- zero_v3(grid->verts[i].velocity_smooth);
- }
-
- for (i = 0; i < grid->res; ++i) {
- for (j = 0; j < grid->res; ++j) {
- for (k = 0; k < grid->res; ++k) {
- hair_volume_filter_box_convolute(grid, invD, kernel_sizev, i, j, k);
- }
- }
- }
-
- /* apply as new velocity */
- for (i = 0; i < size; ++i) {
- copy_v3_v3(grid->verts[i].velocity, grid->verts[i].velocity_smooth);
- }
+ int size = hair_grid_size(grid->res);
+ int kernel_sizev[3] = {kernel_size, kernel_size, kernel_size};
+ int tot;
+ float invD;
+ int i, j, k;
+
+ if (kernel_size <= 0)
+ return;
+
+ tot = kernel_size * 2 + 1;
+ invD = 1.0f / (float)(tot * tot * tot);
+
+ /* clear values for convolution */
+ for (i = 0; i < size; ++i) {
+ zero_v3(grid->verts[i].velocity_smooth);
+ }
+
+ for (i = 0; i < grid->res; ++i) {
+ for (j = 0; j < grid->res; ++j) {
+ for (k = 0; k < grid->res; ++k) {
+ hair_volume_filter_box_convolute(grid, invD, kernel_sizev, i, j, k);
+ }
+ }
+ }
+
+ /* apply as new velocity */
+ for (i = 0; i < size; ++i) {
+ copy_v3_v3(grid->verts[i].velocity, grid->verts[i].velocity_smooth);
+ }
}
#endif
-HairGrid *BPH_hair_volume_create_vertex_grid(float cellsize, 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 scale;
- float extent[3];
- int resmin[3], resmax[3], res[3];
- float gmin_margin[3], gmax_margin[3];
- int size;
- HairGrid *grid;
- int i;
-
- /* sanity check */
- if (cellsize <= 0.0f)
- cellsize = 1.0f;
- scale = 1.0f / cellsize;
-
- sub_v3_v3v3(extent, gmax, gmin);
- for (i = 0; i < 3; ++i) {
- resmin[i] = floor_int(gmin[i] * scale);
- resmax[i] = floor_int(gmax[i] * scale) + 1;
-
- /* add margin of 1 cell */
- resmin[i] -= 1;
- resmax[i] += 1;
-
- res[i] = resmax[i] - resmin[i] + 1;
- /* sanity check: avoid null-sized grid */
- if (res[i] < 4) {
- res[i] = 4;
- resmax[i] = resmin[i] + 4;
- }
- /* 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);
-
- grid = (HairGrid *)MEM_callocN(sizeof(HairGrid), "hair grid");
- 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);
- grid->cellsize = cellsize;
- grid->inv_cellsize = scale;
- grid->verts = (HairGridVert *)MEM_callocN(sizeof(HairGridVert) * size, "hair voxel data");
-
- return grid;
+ 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;
+
+ /* sanity check */
+ if (cellsize <= 0.0f)
+ cellsize = 1.0f;
+ scale = 1.0f / cellsize;
+
+ sub_v3_v3v3(extent, gmax, gmin);
+ for (i = 0; i < 3; ++i) {
+ resmin[i] = floor_int(gmin[i] * scale);
+ resmax[i] = floor_int(gmax[i] * scale) + 1;
+
+ /* add margin of 1 cell */
+ resmin[i] -= 1;
+ resmax[i] += 1;
+
+ res[i] = resmax[i] - resmin[i] + 1;
+ /* sanity check: avoid null-sized grid */
+ if (res[i] < 4) {
+ res[i] = 4;
+ resmax[i] = resmin[i] + 4;
+ }
+ /* 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);
+
+ grid = (HairGrid *)MEM_callocN(sizeof(HairGrid), "hair grid");
+ 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);
+ grid->cellsize = cellsize;
+ grid->inv_cellsize = scale;
+ grid->verts = (HairGridVert *)MEM_callocN(sizeof(HairGridVert) * size, "hair voxel data");
+
+ return grid;
}
void BPH_hair_volume_free_vertex_grid(HairGrid *grid)
{
- if (grid) {
- if (grid->verts)
- MEM_freeN(grid->verts);
- MEM_freeN(grid);
- }
+ if (grid) {
+ if (grid->verts)
+ MEM_freeN(grid->verts);
+ MEM_freeN(grid);
+ }
}
-void BPH_hair_volume_grid_geometry(HairGrid *grid, float *cellsize, 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) *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);
+ 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);
}
#if 0
static HairGridVert *hair_volume_create_collision_grid(ClothModifierData *clmd, lfVector *lX, unsigned int numverts)
{
- int res = hair_grid_res;
- int size = hair_grid_size(res);
- HairGridVert *collgrid;
- ListBase *colliders;
- ColliderCache *col = NULL;
- float gmin[3], gmax[3], scale[3];
- /* 2.0f is an experimental value that seems to give good results */
- float collfac = 2.0f * clmd->sim_parms->collider_friction;
- unsigned int v = 0;
- int i = 0;
-
- hair_volume_get_boundbox(lX, numverts, gmin, gmax);
- hair_grid_get_scale(res, gmin, gmax, scale);
-
- collgrid = MEM_mallocN(sizeof(HairGridVert) * size, "hair collider voxel data");
-
- /* initialize grid */
- for (i = 0; i < size; ++i) {
- zero_v3(collgrid[i].velocity);
- collgrid[i].density = 0.0f;
- }
-
- /* gather colliders */
- colliders = BKE_collider_cache_create(depsgraph, 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];
- float weights[8];
- int di, dj, dk;
-
- for (v = 0; v < col->collmd->numverts; v++, loc0++, loc1++) {
- int offset;
-
- if (!hair_grid_point_valid(loc1->co, gmin, gmax))
- continue;
-
- offset = hair_grid_weights(res, gmin, scale, lX[v], weights);
-
- sub_v3_v3v3(vel, loc1->co, loc0->co);
-
- 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;
-
- collgrid[voffset].density += weights[iw];
- madd_v3_v3fl(collgrid[voffset].velocity, vel, weights[iw]);
- }
- }
- }
- }
- }
- }
- BKE_collider_cache_free(&colliders);
-
- /* divide velocity with density */
- for (i = 0; i < size; i++) {
- float density = collgrid[i].density;
- if (density > 0.0f)
- mul_v3_fl(collgrid[i].velocity, 1.0f / density);
- }
-
- return collgrid;
+ int res = hair_grid_res;
+ int size = hair_grid_size(res);
+ HairGridVert *collgrid;
+ ListBase *colliders;
+ ColliderCache *col = NULL;
+ float gmin[3], gmax[3], scale[3];
+ /* 2.0f is an experimental value that seems to give good results */
+ float collfac = 2.0f * clmd->sim_parms->collider_friction;
+ unsigned int v = 0;
+ int i = 0;
+
+ hair_volume_get_boundbox(lX, numverts, gmin, gmax);
+ hair_grid_get_scale(res, gmin, gmax, scale);
+
+ collgrid = MEM_mallocN(sizeof(HairGridVert) * size, "hair collider voxel data");
+
+ /* initialize grid */
+ for (i = 0; i < size; ++i) {
+ zero_v3(collgrid[i].velocity);
+ collgrid[i].density = 0.0f;
+ }
+
+ /* gather colliders */
+ colliders = BKE_collider_cache_create(depsgraph, 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];
+ float weights[8];
+ int di, dj, dk;
+
+ for (v = 0; v < col->collmd->numverts; v++, loc0++, loc1++) {
+ int offset;
+
+ if (!hair_grid_point_valid(loc1->co, gmin, gmax))
+ continue;
+
+ offset = hair_grid_weights(res, gmin, scale, lX[v], weights);
+
+ sub_v3_v3v3(vel, loc1->co, loc0->co);
+
+ 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;
+
+ collgrid[voffset].density += weights[iw];
+ madd_v3_v3fl(collgrid[voffset].velocity, vel, weights[iw]);
+ }
+ }
+ }
+ }
+ }
+ }
+ BKE_collider_cache_free(&colliders);
+
+ /* divide velocity with density */
+ for (i = 0; i < size; i++) {
+ float density = collgrid[i].density;
+ if (density > 0.0f)
+ mul_v3_fl(collgrid[i].velocity, 1.0f / density);
+ }
+
+ return collgrid;
}
#endif