Blender V5.0
hair_volume.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2015-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "MEM_guardedalloc.h"
10
11#include "BLI_math_matrix.h"
12#include "BLI_math_vector.h"
13
14#include "eigen_utils.h"
15#include "implicit.h"
16
17/* ================ Volumetric Hair Interaction ================
18 * adapted from
19 *
20 * Volumetric Methods for Simulation and Rendering of Hair
21 * (Petrovic, Henne, Anderson, Pixar Technical Memo #06-08, Pixar Animation Studios)
22 *
23 * as well as
24 *
25 * "Detail Preserving Continuum Simulation of Straight Hair"
26 * (McAdams, Selle 2009)
27 */
28
29/* Note about array indexing:
30 * Generally the arrays here are one-dimensional.
31 * The relation between 3D indices and the array offset is
32 * offset = x + res_x * y + res_x * res_y * z
33 */
34
35static float I[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
36
37BLI_INLINE int floor_int(float value)
38{
39 return value > 0.0f ? int(value) : int(value) - 1;
40}
41
42BLI_INLINE float floor_mod(float value)
43{
44 return value - floorf(value);
45}
46
47BLI_INLINE int hair_grid_size(const int res[3])
48{
49 return res[0] * res[1] * res[2];
50}
51
54 float velocity[3];
55 float density;
56
58};
59
60struct HairGrid {
62 int res[3];
63 float gmin[3], gmax[3];
65};
66
67#define HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, axis) \
68 min_ii(max_ii(int((vec[axis] - gmin[axis]) * scale), 0), res[axis] - 2)
69
70BLI_INLINE int hair_grid_offset(const float vec[3],
71 const int res[3],
72 const float gmin[3],
73 float scale)
74{
75 int i, j, k;
76 i = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 0);
77 j = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 1);
78 k = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 2);
79 return i + (j + k * res[1]) * res[0];
80}
81
83 const int res[3], const float gmin[3], float scale, const float vec[3], float uvw[3])
84{
85 int i, j, k, offset;
86
87 i = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 0);
88 j = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 1);
89 k = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 2);
90 offset = i + (j + k * res[1]) * res[0];
91
92 uvw[0] = (vec[0] - gmin[0]) * scale - float(i);
93 uvw[1] = (vec[1] - gmin[1]) * scale - float(j);
94 uvw[2] = (vec[2] - gmin[2]) * scale - float(k);
95
96#if 0
97 BLI_assert(0.0f <= uvw[0] && uvw[0] <= 1.0001f);
98 BLI_assert(0.0f <= uvw[1] && uvw[1] <= 1.0001f);
99 BLI_assert(0.0f <= uvw[2] && uvw[2] <= 1.0001f);
100#endif
101
102 return offset;
103}
104
106 const int res[3],
107 const float gmin[3],
108 float scale,
109 const float vec[3],
110 float *density,
111 float velocity[3],
112 float vel_smooth[3],
113 float density_gradient[3],
114 float velocity_gradient[3][3])
115{
117 float uvw[3], muvw[3];
118 int res2 = res[1] * res[0];
119 int offset;
120
121 offset = hair_grid_interp_weights(res, gmin, scale, vec, uvw);
122 muvw[0] = 1.0f - uvw[0];
123 muvw[1] = 1.0f - uvw[1];
124 muvw[2] = 1.0f - uvw[2];
125
126 data[0] = grid[offset];
127 data[1] = grid[offset + 1];
128 data[2] = grid[offset + res[0]];
129 data[3] = grid[offset + res[0] + 1];
130 data[4] = grid[offset + res2];
131 data[5] = grid[offset + res2 + 1];
132 data[6] = grid[offset + res2 + res[0]];
133 data[7] = grid[offset + res2 + res[0] + 1];
134
135 if (density) {
136 *density = muvw[2] * (muvw[1] * (muvw[0] * data[0].density + uvw[0] * data[1].density) +
137 uvw[1] * (muvw[0] * data[2].density + uvw[0] * data[3].density)) +
138 uvw[2] * (muvw[1] * (muvw[0] * data[4].density + uvw[0] * data[5].density) +
139 uvw[1] * (muvw[0] * data[6].density + uvw[0] * data[7].density));
140 }
141
142 if (velocity) {
143 int k;
144 for (k = 0; k < 3; k++) {
145 velocity[k] = muvw[2] *
146 (muvw[1] * (muvw[0] * data[0].velocity[k] + uvw[0] * data[1].velocity[k]) +
147 uvw[1] * (muvw[0] * data[2].velocity[k] + uvw[0] * data[3].velocity[k])) +
148 uvw[2] *
149 (muvw[1] * (muvw[0] * data[4].velocity[k] + uvw[0] * data[5].velocity[k]) +
150 uvw[1] * (muvw[0] * data[6].velocity[k] + uvw[0] * data[7].velocity[k]));
151 }
152 }
153
154 if (vel_smooth) {
155 int k;
156 for (k = 0; k < 3; k++) {
157 vel_smooth[k] = muvw[2] * (muvw[1] * (muvw[0] * data[0].velocity_smooth[k] +
158 uvw[0] * data[1].velocity_smooth[k]) +
159 uvw[1] * (muvw[0] * data[2].velocity_smooth[k] +
160 uvw[0] * data[3].velocity_smooth[k])) +
161 uvw[2] * (muvw[1] * (muvw[0] * data[4].velocity_smooth[k] +
162 uvw[0] * data[5].velocity_smooth[k]) +
163 uvw[1] * (muvw[0] * data[6].velocity_smooth[k] +
164 uvw[0] * data[7].velocity_smooth[k]));
165 }
166 }
167
168 if (density_gradient) {
169 density_gradient[0] = muvw[1] * muvw[2] * (data[0].density - data[1].density) +
170 uvw[1] * muvw[2] * (data[2].density - data[3].density) +
171 muvw[1] * uvw[2] * (data[4].density - data[5].density) +
172 uvw[1] * uvw[2] * (data[6].density - data[7].density);
173
174 density_gradient[1] = muvw[2] * muvw[0] * (data[0].density - data[2].density) +
175 uvw[2] * muvw[0] * (data[4].density - data[6].density) +
176 muvw[2] * uvw[0] * (data[1].density - data[3].density) +
177 uvw[2] * uvw[0] * (data[5].density - data[7].density);
178
179 density_gradient[2] = muvw[2] * muvw[0] * (data[0].density - data[4].density) +
180 uvw[2] * muvw[0] * (data[1].density - data[5].density) +
181 muvw[2] * uvw[0] * (data[2].density - data[6].density) +
182 uvw[2] * uvw[0] * (data[3].density - data[7].density);
183 }
184
185 if (velocity_gradient) {
186 /* XXX TODO: */
187 zero_m3(velocity_gradient);
188 }
189}
190
192 const float x[3],
193 const float v[3],
194 float smoothfac,
195 float pressurefac,
196 float minpressure,
197 float f[3],
198 float dfdx[3][3],
199 float dfdv[3][3])
200{
201 float gdensity, gvelocity[3], ggrad[3], gvelgrad[3][3], gradlen;
202
204 grid->res,
205 grid->gmin,
206 grid->inv_cellsize,
207 x,
208 &gdensity,
209 gvelocity,
210 nullptr,
211 ggrad,
212 gvelgrad);
213
214 zero_v3(f);
215 sub_v3_v3(gvelocity, v);
216 mul_v3_v3fl(f, gvelocity, smoothfac);
217
218 gradlen = normalize_v3(ggrad) - minpressure;
219 if (gradlen > 0.0f) {
220 mul_v3_fl(ggrad, gradlen);
221 madd_v3_v3fl(f, ggrad, pressurefac);
222 }
223
224 zero_m3(dfdx);
225
226 sub_m3_m3m3(dfdv, gvelgrad, I);
227 mul_m3_fl(dfdv, smoothfac);
228}
229
231 const float x[3],
232 float *density,
233 float velocity[3],
234 float velocity_smooth[3],
235 float density_gradient[3],
236 float velocity_gradient[3][3])
237{
239 grid->res,
240 grid->gmin,
241 grid->inv_cellsize,
242 x,
243 density,
244 velocity,
245 velocity_smooth,
246 density_gradient,
247 velocity_gradient);
248}
249
251 HairGrid *grid, const float x[3], const float v[3], float fluid_factor, float r_v[3])
252{
253 float gdensity, gvelocity[3], gvel_smooth[3], ggrad[3], gvelgrad[3][3];
254 float v_pic[3], v_flip[3];
255
257 grid->res,
258 grid->gmin,
259 grid->inv_cellsize,
260 x,
261 &gdensity,
262 gvelocity,
263 gvel_smooth,
264 ggrad,
265 gvelgrad);
266
267 /* velocity according to PIC method (Particle-in-Cell) */
268 copy_v3_v3(v_pic, gvel_smooth);
269
270 /* velocity according to FLIP method (Fluid-Implicit-Particle) */
271 sub_v3_v3v3(v_flip, gvel_smooth, gvelocity);
272 add_v3_v3(v_flip, v);
273
274 interp_v3_v3v3(r_v, v_pic, v_flip, fluid_factor);
275}
276
278{
279 const int size = hair_grid_size(grid->res);
280 int i;
281 for (i = 0; i < size; i++) {
282 zero_v3(grid->verts[i].velocity);
284 grid->verts[i].density = 0.0f;
285 grid->verts[i].samples = 0;
286 }
287}
288
289BLI_INLINE bool hair_grid_point_valid(const float vec[3], const float gmin[3], const float gmax[3])
290{
291 return !(vec[0] < gmin[0] || vec[1] < gmin[1] || vec[2] < gmin[2] || vec[0] > gmax[0] ||
292 vec[1] > gmax[1] || vec[2] > gmax[2]);
293}
294
295BLI_INLINE float dist_tent_v3f3(const float a[3], float x, float y, float z)
296{
297 float w = (1.0f - fabsf(a[0] - x)) * (1.0f - fabsf(a[1] - y)) * (1.0f - fabsf(a[2] - z));
298 return w;
299}
300
301BLI_INLINE float weights_sum(const float weights[8])
302{
303 float totweight = 0.0f;
304 int i;
305 for (i = 0; i < 8; i++) {
306 totweight += weights[i];
307 }
308 return totweight;
309}
310
311/* returns the grid array offset as well to avoid redundant calculation */
313 const int res[3], const float gmin[3], float scale, const float vec[3], float weights[8])
314{
315 int i, j, k, offset;
316 float uvw[3];
317
318 i = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 0);
319 j = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 1);
320 k = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 2);
321 offset = i + (j + k * res[1]) * res[0];
322
323 uvw[0] = (vec[0] - gmin[0]) * scale;
324 uvw[1] = (vec[1] - gmin[1]) * scale;
325 uvw[2] = (vec[2] - gmin[2]) * scale;
326
327 weights[0] = dist_tent_v3f3(uvw, float(i), float(j), float(k));
328 weights[1] = dist_tent_v3f3(uvw, float(i + 1), float(j), float(k));
329 weights[2] = dist_tent_v3f3(uvw, float(i), float(j + 1), float(k));
330 weights[3] = dist_tent_v3f3(uvw, float(i + 1), float(j + 1), float(k));
331 weights[4] = dist_tent_v3f3(uvw, float(i), float(j), float(k + 1));
332 weights[5] = dist_tent_v3f3(uvw, float(i + 1), float(j), float(k + 1));
333 weights[6] = dist_tent_v3f3(uvw, float(i), float(j + 1), float(k + 1));
334 weights[7] = dist_tent_v3f3(uvw, float(i + 1), float(j + 1), float(k + 1));
335
336 // BLI_assert(fabsf(weights_sum(weights) - 1.0f) < 0.0001f);
337
338 return offset;
339}
340
341BLI_INLINE void grid_to_world(HairGrid *grid, float vecw[3], const float vec[3])
342{
343 copy_v3_v3(vecw, vec);
344 mul_v3_fl(vecw, grid->cellsize);
345 add_v3_v3(vecw, grid->gmin);
346}
347
348void SIM_hair_volume_add_vertex(HairGrid *grid, const float x[3], const float v[3])
349{
350 const int res[3] = {grid->res[0], grid->res[1], grid->res[2]};
351 float weights[8];
352 int di, dj, dk;
353 int offset;
354
355 if (!hair_grid_point_valid(x, grid->gmin, grid->gmax)) {
356 return;
357 }
358
359 offset = hair_grid_weights(res, grid->gmin, grid->inv_cellsize, x, weights);
360
361 for (di = 0; di < 2; di++) {
362 for (dj = 0; dj < 2; dj++) {
363 for (dk = 0; dk < 2; dk++) {
364 int voffset = offset + di + (dj + dk * res[1]) * res[0];
365 int iw = di + dj * 2 + dk * 4;
366
367 grid->verts[voffset].density += weights[iw];
368 madd_v3_v3fl(grid->verts[voffset].velocity, v, weights[iw]);
369 }
370 }
371 }
372}
373
374#if 0
375BLI_INLINE void hair_volume_eval_grid_vertex(HairGridVert *vert,
376 const float loc[3],
377 float radius,
378 float dist_scale,
379 const float x2[3],
380 const float v2[3],
381 const float x3[3],
382 const float v3[3])
383{
384 float closest[3], lambda, dist, weight;
385
386 lambda = closest_to_line_v3(closest, loc, x2, x3);
387 dist = len_v3v3(closest, loc);
388
389 weight = (radius - dist) * dist_scale;
390
391 if (weight > 0.0f) {
392 float vel[3];
393
394 interp_v3_v3v3(vel, v2, v3, lambda);
395 madd_v3_v3fl(vert->velocity, vel, weight);
396 vert->density += weight;
397 vert->samples += 1;
398 }
399}
400
401BLI_INLINE int major_axis_v3(const float v[3])
402{
403 const float a = fabsf(v[0]);
404 const float b = fabsf(v[1]);
405 const float c = fabsf(v[2]);
406 return a > b ? (a > c ? 0 : 2) : (b > c ? 1 : 2);
407}
408
409BLI_INLINE void hair_volume_add_segment_2D(HairGrid *grid,
410 const float /*x1*/ [3],
411 const float /*v1*/ [3]),
412 const float x2[3],
413 const float v2[3],
414 const float x3[3],
415 const float v3[3],
416 const float /*x4*/ [3],
417 const float /*v4*/ [3],
418 const float /*dir1*/[3],
419 const float dir2[3],
420 const float /*dir3*/ [3],
421 int resj,
422 int resk,
423 int jmin,
424 int jmax,
425 int kmin,
426 int kmax,
427 HairGridVert *vert,
428 int stride_j,
429 int stride_k,
430 const float loc[3],
431 int axis_j,
432 int axis_k,
433 int debug_i)
434{
435 const float radius = 1.5f;
436 const float dist_scale = grid->inv_cellsize;
437
438 int j, k;
439
440 /* boundary checks to be safe */
441 CLAMP_MIN(jmin, 0);
442 CLAMP_MAX(jmax, resj - 1);
443 CLAMP_MIN(kmin, 0);
444 CLAMP_MAX(kmax, resk - 1);
445
446 HairGridVert *vert_j = vert + jmin * stride_j;
447 float loc_j[3] = {loc[0], loc[1], loc[2]};
448 loc_j[axis_j] += float(jmin);
449 for (j = jmin; j <= jmax; j++, vert_j += stride_j, loc_j[axis_j] += 1.0f) {
450
451 HairGridVert *vert_k = vert_j + kmin * stride_k;
452 float loc_k[3] = {loc_j[0], loc_j[1], loc_j[2]};
453 loc_k[axis_k] += float(kmin);
454 for (k = kmin; k <= kmax; k++, vert_k += stride_k, loc_k[axis_k] += 1.0f) {
455
456 hair_volume_eval_grid_vertex(vert_k, loc_k, radius, dist_scale, x2, v2, x3, v3);
457
458# if 0
459 {
460 float wloc[3], x2w[3], x3w[3];
461 grid_to_world(grid, wloc, loc_k);
462 grid_to_world(grid, x2w, x2);
463 grid_to_world(grid, x3w, x3);
464
465 if (vert_k->samples > 0) {
466 BKE_sim_debug_data_add_circle(wloc, 0.01f, 1.0, 1.0, 0.3, "grid", 2525, debug_i, j, k);
467 }
468
469 if (grid->debug_value) {
470 BKE_sim_debug_data_add_dot(wloc, 1, 0, 0, "grid", 93, debug_i, j, k);
471 BKE_sim_debug_data_add_dot(x2w, 0.1, 0.1, 0.7, "grid", 649, debug_i, j, k);
472 BKE_sim_debug_data_add_line(wloc, x2w, 0.3, 0.8, 0.3, "grid", 253, debug_i, j, k);
473 BKE_sim_debug_data_add_line(wloc, x3w, 0.8, 0.3, 0.3, "grid", 254, debug_i, j, k);
474# if 0
476 x2w, len_v3v3(wloc, x2w), 0.2, 0.7, 0.2, "grid", 255, i, j, k);
477# endif
478 }
479 }
480# endif
481 }
482 }
483}
484
485/* Uses a variation of Bresenham's algorithm for rasterizing a 3D grid with a line segment.
486 *
487 * The radius of influence around a segment is assumed to be at most 2*cellsize,
488 * i.e. only cells containing the segment and their direct neighbors are examined.
489 */
491 const float x1[3],
492 const float v1[3],
493 const float x2[3],
494 const float v2[3],
495 const float x3[3],
496 const float v3[3],
497 const float x4[3],
498 const float v4[3],
499 const float dir1[3],
500 const float dir2[3],
501 const float dir3[3])
502{
503 const int res[3] = {grid->res[0], grid->res[1], grid->res[2]};
504
505 /* find the primary direction from the major axis of the direction vector */
506 const int axis0 = major_axis_v3(dir2);
507 const int axis1 = (axis0 + 1) % 3;
508 const int axis2 = (axis0 + 2) % 3;
509
510 /* vertex buffer offset factors along cardinal axes */
511 const int strides[3] = {1, res[0], res[0] * res[1]};
512 const int stride0 = strides[axis0];
513 const int stride1 = strides[axis1];
514 const int stride2 = strides[axis2];
515
516 /* increment of secondary directions per step in the primary direction
517 * NOTE: we always go in the positive direction along axis0, so the sign can be inverted
518 */
519 const float inc1 = dir2[axis1] / dir2[axis0];
520 const float inc2 = dir2[axis2] / dir2[axis0];
521
522 /* start/end points, so increment along axis0 is always positive */
523 const float *start = x2[axis0] < x3[axis0] ? x2 : x3;
524 const float *end = x2[axis0] < x3[axis0] ? x3 : x2;
525 const float start0 = start[axis0], start1 = start[axis1], start2 = start[axis2];
526 const float end0 = end[axis0];
527
528 /* range along primary direction */
529 const int imin = max_ii(floor_int(start[axis0]) - 1, 0);
530 const int imax = min_ii(floor_int(end[axis0]) + 2, res[axis0] - 1);
531
532 float h = 0.0f;
533 HairGridVert *vert0;
534 float loc0[3];
535 int j0, k0, j0_prev, k0_prev;
536 int i;
537
538 for (i = imin; i <= imax; i++) {
539 float shift1, shift2; /* fraction of a full cell shift [0.0, 1.0) */
540 int jmin, jmax, kmin, kmax;
541
542 h = std::clamp(float(i), start0, end0);
543
544 shift1 = start1 + (h - start0) * inc1;
545 shift2 = start2 + (h - start0) * inc2;
546
547 j0_prev = j0;
548 j0 = floor_int(shift1);
549
550 k0_prev = k0;
551 k0 = floor_int(shift2);
552
553 if (i > imin) {
554 jmin = min_ii(j0, j0_prev);
555 jmax = max_ii(j0, j0_prev);
556 kmin = min_ii(k0, k0_prev);
557 kmax = max_ii(k0, k0_prev);
558 }
559 else {
560 jmin = jmax = j0;
561 kmin = kmax = k0;
562 }
563
564 vert0 = grid->verts + i * stride0;
565 loc0[axis0] = float(i);
566 loc0[axis1] = 0.0f;
567 loc0[axis2] = 0.0f;
568
569 hair_volume_add_segment_2D(grid,
570 x1,
571 v1,
572 x2,
573 v2,
574 x3,
575 v3,
576 x4,
577 v4,
578 dir1,
579 dir2,
580 dir3,
581 res[axis1],
582 res[axis2],
583 jmin - 1,
584 jmax + 2,
585 kmin - 1,
586 kmax + 2,
587 vert0,
588 stride1,
589 stride2,
590 loc0,
591 axis1,
592 axis2,
593 i);
594 }
595}
596#else
598 const float loc[3],
599 float radius,
600 float dist_scale,
601 const float x[3],
602 const float v[3])
603{
604 float dist, weight;
605
606 dist = len_v3v3(x, loc);
607
608 weight = (radius - dist) * dist_scale;
609
610 if (weight > 0.0f) {
611 madd_v3_v3fl(vert->velocity, v, weight);
612 vert->density += weight;
613 vert->samples += 1;
614 }
615}
616
618 const float /*x1*/[3],
619 const float /*v1*/[3],
620 const float x2[3],
621 const float v2[3],
622 const float x3[3],
623 const float v3[3],
624 const float /*x4*/[3],
625 const float /*v4*/[3],
626 const float /*dir1*/[3],
627 const float /*dir2*/[3],
628 const float /*dir3*/[3])
629{
630 /* XXX simplified test implementation using a series of discrete sample along the segment,
631 * instead of finding the closest point for all affected grid vertices. */
632
633 const float radius = 1.5f;
634 const float dist_scale = grid->inv_cellsize;
635
636 const int res[3] = {grid->res[0], grid->res[1], grid->res[2]};
637 const int stride[3] = {1, res[0], res[0] * res[1]};
638 const int num_samples = 10;
639
640 int s;
641
642 for (s = 0; s < num_samples; s++) {
643 float x[3], v[3];
644 int i, j, k;
645
646 float f = float(s) / float(num_samples - 1);
647 interp_v3_v3v3(x, x2, x3, f);
648 interp_v3_v3v3(v, v2, v3, f);
649
650 int imin = max_ii(floor_int(x[0]) - 2, 0);
651 int imax = min_ii(floor_int(x[0]) + 2, res[0] - 1);
652 int jmin = max_ii(floor_int(x[1]) - 2, 0);
653 int jmax = min_ii(floor_int(x[1]) + 2, res[1] - 1);
654 int kmin = max_ii(floor_int(x[2]) - 2, 0);
655 int kmax = min_ii(floor_int(x[2]) + 2, res[2] - 1);
656
657 for (k = kmin; k <= kmax; k++) {
658 for (j = jmin; j <= jmax; j++) {
659 for (i = imin; i <= imax; i++) {
660 float loc[3] = {float(i), float(j), float(k)};
661 HairGridVert *vert = grid->verts + i * stride[0] + j * stride[1] + k * stride[2];
662
663 hair_volume_eval_grid_vertex_sample(vert, loc, radius, dist_scale, x, v);
664 }
665 }
666 }
667 }
668}
669#endif
670
672{
673 int i, size = hair_grid_size(grid->res);
674 /* divide velocity with density */
675 for (i = 0; i < size; i++) {
676 float density = grid->verts[i].density;
677 if (density > 0.0f) {
678 mul_v3_fl(grid->verts[i].velocity, 1.0f / density);
679 }
680 }
681}
682
683/* Cells with density below this are considered empty. */
684static const float density_threshold = 0.001f;
685
686/* Contribution of target density pressure to the laplacian in the pressure poisson equation.
687 * This is based on the model found in
688 * "Two-way Coupled SPH and Particle Level Set Fluid Simulation" (Losasso et al., 2008)
689 */
691 float target_density,
692 float strength)
693{
694 if (density > density_threshold && density > target_density) {
695 return strength * logf(target_density / density);
696 }
697
698 return 0.0f;
699}
700
702 float /*dt*/,
703 float target_density,
704 float target_strength)
705{
706 const float flowfac = grid->cellsize;
707 const float inv_flowfac = 1.0f / grid->cellsize;
708
709 // const int num_cells = hair_grid_size(grid->res);
710 const int res[3] = {grid->res[0], grid->res[1], grid->res[2]};
711 const int resA[3] = {grid->res[0] + 2, grid->res[1] + 2, grid->res[2] + 2};
712
713 const int stride0 = 1;
714 const int stride1 = grid->res[0];
715 const int stride2 = grid->res[1] * grid->res[0];
716 const int strideA0 = 1;
717 const int strideA1 = grid->res[0] + 2;
718 const int strideA2 = (grid->res[1] + 2) * (grid->res[0] + 2);
719
720 const int num_cells = res[0] * res[1] * res[2];
721 const int num_cellsA = (res[0] + 2) * (res[1] + 2) * (res[2] + 2);
722
723 HairGridVert *vert_start = grid->verts - (stride0 + stride1 + stride2);
724 HairGridVert *vert;
725 int i, j, k;
726
727#define MARGIN_i0 (i < 1)
728#define MARGIN_j0 (j < 1)
729#define MARGIN_k0 (k < 1)
730#define MARGIN_i1 (i >= resA[0] - 1)
731#define MARGIN_j1 (j >= resA[1] - 1)
732#define MARGIN_k1 (k >= resA[2] - 1)
733
734#define NEIGHBOR_MARGIN_i0 (i < 2)
735#define NEIGHBOR_MARGIN_j0 (j < 2)
736#define NEIGHBOR_MARGIN_k0 (k < 2)
737#define NEIGHBOR_MARGIN_i1 (i >= resA[0] - 2)
738#define NEIGHBOR_MARGIN_j1 (j >= resA[1] - 2)
739#define NEIGHBOR_MARGIN_k1 (k >= resA[2] - 2)
740
741 BLI_assert(num_cells >= 1);
742
743 /* Calculate divergence */
744 lVector B(num_cellsA);
745 for (k = 0; k < resA[2]; k++) {
746 for (j = 0; j < resA[1]; j++) {
747 for (i = 0; i < resA[0]; i++) {
748 int u = i * strideA0 + j * strideA1 + k * strideA2;
749 bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 ||
750 MARGIN_k1;
751
752 if (is_margin) {
753 B[u] = 0.0f;
754 continue;
755 }
756
757 vert = vert_start + i * stride0 + j * stride1 + k * stride2;
758
759 const float *v0 = vert->velocity;
760 float dx = 0.0f, dy = 0.0f, dz = 0.0f;
761 if (!NEIGHBOR_MARGIN_i0) {
762 dx += v0[0] - (vert - stride0)->velocity[0];
763 }
764 if (!NEIGHBOR_MARGIN_i1) {
765 dx += (vert + stride0)->velocity[0] - v0[0];
766 }
767 if (!NEIGHBOR_MARGIN_j0) {
768 dy += v0[1] - (vert - stride1)->velocity[1];
769 }
770 if (!NEIGHBOR_MARGIN_j1) {
771 dy += (vert + stride1)->velocity[1] - v0[1];
772 }
773 if (!NEIGHBOR_MARGIN_k0) {
774 dz += v0[2] - (vert - stride2)->velocity[2];
775 }
776 if (!NEIGHBOR_MARGIN_k1) {
777 dz += (vert + stride2)->velocity[2] - v0[2];
778 }
779
780 float divergence = -0.5f * flowfac * (dx + dy + dz);
781
782 /* adjustment term for target density */
783 float target = hair_volume_density_divergence(
784 vert->density, target_density, target_strength);
785
786 /* B vector contains the finite difference approximation of the velocity divergence.
787 * NOTE: according to the discretized Navier-Stokes equation the RHS vector
788 * and resulting pressure gradient should be multiplied by the (inverse) density;
789 * however, this is already included in the weighting of hair velocities on the grid!
790 */
791 B[u] = divergence - target;
792
793#if 0
794 {
795 float wloc[3], loc[3];
796 float col0[3] = {0.0, 0.0, 0.0};
797 float colp[3] = {0.0, 1.0, 1.0};
798 float coln[3] = {1.0, 0.0, 1.0};
799 float col[3];
800 float fac;
801
802 loc[0] = float(i - 1);
803 loc[1] = float(j - 1);
804 loc[2] = float(k - 1);
805 grid_to_world(grid, wloc, loc);
806
807 if (divergence > 0.0f) {
808 fac = std::clamp(divergence * target_strength, 0.0, 1.0);
809 interp_v3_v3v3(col, col0, colp, fac);
810 }
811 else {
812 fac = std::clamp(-divergence * target_strength, 0.0, 1.0);
813 interp_v3_v3v3(col, col0, coln, fac);
814 }
815 if (fac > 0.05f) {
817 grid->debug_data, wloc, 0.01f, col[0], col[1], col[2], "grid", 5522, i, j, k);
818 }
819 }
820#endif
821 }
822 }
823 }
824
825 /* Main Poisson equation system:
826 * This is derived from the discretization of the Poisson equation:
827 * `div(grad(p)) = div(v)`
828 *
829 * The finite difference approximation yields the linear equation system described here:
830 * https://en.wikipedia.org/wiki/Discrete_Poisson_equation
831 */
832 lMatrix A(num_cellsA, num_cellsA);
833 /* Reserve space for the base equation system (without boundary conditions).
834 * Each column contains a factor 6 on the diagonal
835 * and up to 6 factors -1 on other places.
836 */
837 A.reserve(Eigen::VectorXi::Constant(num_cellsA, 7));
838
839 for (k = 0; k < resA[2]; k++) {
840 for (j = 0; j < resA[1]; j++) {
841 for (i = 0; i < resA[0]; i++) {
842 int u = i * strideA0 + j * strideA1 + k * strideA2;
843 bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 ||
844 MARGIN_k1;
845
846 vert = vert_start + i * stride0 + j * stride1 + k * stride2;
847 if (!is_margin && vert->density > density_threshold) {
848 int neighbors_lo = 0;
849 int neighbors_hi = 0;
850 int non_solid_neighbors = 0;
851 int neighbor_lo_index[3];
852 int neighbor_hi_index[3];
853 int n;
854
855 /* check for upper bounds in advance
856 * to get the correct number of neighbors,
857 * needed for the diagonal element
858 */
859 if (!NEIGHBOR_MARGIN_k0 && (vert - stride2)->density > density_threshold) {
860 neighbor_lo_index[neighbors_lo++] = u - strideA2;
861 }
862 if (!NEIGHBOR_MARGIN_j0 && (vert - stride1)->density > density_threshold) {
863 neighbor_lo_index[neighbors_lo++] = u - strideA1;
864 }
865 if (!NEIGHBOR_MARGIN_i0 && (vert - stride0)->density > density_threshold) {
866 neighbor_lo_index[neighbors_lo++] = u - strideA0;
867 }
868 if (!NEIGHBOR_MARGIN_i1 && (vert + stride0)->density > density_threshold) {
869 neighbor_hi_index[neighbors_hi++] = u + strideA0;
870 }
871 if (!NEIGHBOR_MARGIN_j1 && (vert + stride1)->density > density_threshold) {
872 neighbor_hi_index[neighbors_hi++] = u + strideA1;
873 }
874 if (!NEIGHBOR_MARGIN_k1 && (vert + stride2)->density > density_threshold) {
875 neighbor_hi_index[neighbors_hi++] = u + strideA2;
876 }
877
878 // int liquid_neighbors = neighbors_lo + neighbors_hi;
879 non_solid_neighbors = 6;
880
881 for (n = 0; n < neighbors_lo; n++) {
882 A.insert(neighbor_lo_index[n], u) = -1.0f;
883 }
884 A.insert(u, u) = float(non_solid_neighbors);
885 for (n = 0; n < neighbors_hi; n++) {
886 A.insert(neighbor_hi_index[n], u) = -1.0f;
887 }
888 }
889 else {
890 A.insert(u, u) = 1.0f;
891 }
892 }
893 }
894 }
895
897 cg.setMaxIterations(100);
898 cg.setTolerance(0.01f);
899
900 cg.compute(A);
901
902 lVector p = cg.solve(B);
903
904 if (cg.info() == Eigen::Success) {
905 /* Calculate velocity = grad(p) */
906 for (k = 0; k < resA[2]; k++) {
907 for (j = 0; j < resA[1]; j++) {
908 for (i = 0; i < resA[0]; i++) {
909 int u = i * strideA0 + j * strideA1 + k * strideA2;
910 bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 ||
911 MARGIN_k1;
912 if (is_margin) {
913 continue;
914 }
915
916 vert = vert_start + i * stride0 + j * stride1 + k * stride2;
917 if (vert->density > density_threshold) {
918 float p_left = p[u - strideA0];
919 float p_right = p[u + strideA0];
920 float p_down = p[u - strideA1];
921 float p_up = p[u + strideA1];
922 float p_bottom = p[u - strideA2];
923 float p_top = p[u + strideA2];
924
925 /* finite difference estimate of pressure gradient */
926 float dvel[3];
927 dvel[0] = p_right - p_left;
928 dvel[1] = p_up - p_down;
929 dvel[2] = p_top - p_bottom;
930 mul_v3_fl(dvel, -0.5f * inv_flowfac);
931
932 /* pressure gradient describes velocity delta */
933 add_v3_v3v3(vert->velocity_smooth, vert->velocity, dvel);
934 }
935 else {
937 }
938 }
939 }
940 }
941
942#if 0
943 {
944 int axis = 0;
945 float offset = 0.0f;
946
947 int slice = (offset - grid->gmin[axis]) / grid->cellsize;
948
949 for (k = 0; k < resA[2]; k++) {
950 for (j = 0; j < resA[1]; j++) {
951 for (i = 0; i < resA[0]; i++) {
952 int u = i * strideA0 + j * strideA1 + k * strideA2;
953 bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 ||
954 MARGIN_k1;
955 if (i != slice) {
956 continue;
957 }
958
959 vert = vert_start + i * stride0 + j * stride1 + k * stride2;
960
961 float wloc[3], loc[3];
962 float col0[3] = {0.0, 0.0, 0.0};
963 float colp[3] = {0.0, 1.0, 1.0};
964 float coln[3] = {1.0, 0.0, 1.0};
965 float col[3];
966 float fac;
967
968 loc[0] = float(i - 1);
969 loc[1] = float(j - 1);
970 loc[2] = float(k - 1);
971 grid_to_world(grid, wloc, loc);
972
973 float pressure = p[u];
974 if (pressure > 0.0f) {
975 fac = std::clamp(pressure * grid->debug1, 0.0, 1.0);
976 interp_v3_v3v3(col, col0, colp, fac);
977 }
978 else {
979 fac = std::clamp(-pressure * grid->debug1, 0.0, 1.0);
980 interp_v3_v3v3(col, col0, coln, fac);
981 }
982 if (fac > 0.05f) {
984 grid->debug_data, wloc, 0.01f, col[0], col[1], col[2], "grid", 5533, i, j, k);
985 }
986
987 if (!is_margin) {
988 float dvel[3];
989 sub_v3_v3v3(dvel, vert->velocity_smooth, vert->velocity);
990# if 0
992 grid->debug_data, wloc, dvel, 1, 1, 1, "grid", 5566, i, j, k);
993# endif
994 }
995
996 if (!is_margin) {
997 float d = std::clamp(vert->density * grid->debug2, 0.0f, 1.0f);
998 float col0[3] = {0.3, 0.3, 0.3};
999 float colp[3] = {0.0, 0.0, 1.0};
1000 float col[3];
1001
1002 interp_v3_v3v3(col, col0, colp, d);
1003# if 0
1004 if (d > 0.05f) {
1006 grid->debug_data, wloc, col[0], col[1], col[2], "grid", 5544, i, j, k);
1007 }
1008# endif
1009 }
1010 }
1011 }
1012 }
1013 }
1014#endif
1015
1016 return true;
1017 }
1018
1019 /* Clear result in case of error */
1020 for (i = 0, vert = grid->verts; i < num_cells; i++, vert++) {
1021 zero_v3(vert->velocity_smooth);
1022 }
1023
1024 return false;
1025}
1026
1027#if 0 /* XXX weighting is incorrect, disabled for now */
1028/* Velocity filter kernel
1029 * See https://en.wikipedia.org/wiki/Filter_%28large_eddy_simulation%29
1030 */
1031
1032BLI_INLINE void hair_volume_filter_box_convolute(
1033 HairVertexGrid *grid, float invD, const int kernel_size[3], int i, int j, int k)
1034{
1035 int res = grid->res;
1036 int p, q, r;
1037 int minp = max_ii(i - kernel_size[0], 0), maxp = min_ii(i + kernel_size[0], res - 1);
1038 int minq = max_ii(j - kernel_size[1], 0), maxq = min_ii(j + kernel_size[1], res - 1);
1039 int minr = max_ii(k - kernel_size[2], 0), maxr = min_ii(k + kernel_size[2], res - 1);
1040 int offset, kernel_offset, kernel_dq, kernel_dr;
1042 float *vel_smooth;
1043
1044 offset = i + (j + k * res) * res;
1045 verts = grid->verts;
1046 vel_smooth = verts[offset].velocity_smooth;
1047
1048 kernel_offset = minp + (minq + minr * res) * res;
1049 kernel_dq = res;
1050 kernel_dr = res * res;
1051 for (r = minr; r <= maxr; r++) {
1052 for (q = minq; q <= maxq; q++) {
1053 for (p = minp; p <= maxp; p++) {
1054
1055 madd_v3_v3fl(vel_smooth, verts[kernel_offset].velocity, invD);
1056
1057 kernel_offset += 1;
1058 }
1059 kernel_offset += kernel_dq;
1060 }
1061 kernel_offset += kernel_dr;
1062 }
1063}
1064
1065void SIM_hair_volume_vertex_grid_filter_box(HairVertexGrid *grid, int kernel_size)
1066{
1067 int size = hair_grid_size(grid->res);
1068 int kernel_sizev[3] = {kernel_size, kernel_size, kernel_size};
1069 int tot;
1070 float invD;
1071 int i, j, k;
1072
1073 if (kernel_size <= 0) {
1074 return;
1075 }
1076
1077 tot = kernel_size * 2 + 1;
1078 invD = 1.0f / float(tot * tot * tot);
1079
1080 /* clear values for convolution */
1081 for (i = 0; i < size; i++) {
1082 zero_v3(grid->verts[i].velocity_smooth);
1083 }
1084
1085 for (i = 0; i < grid->res; i++) {
1086 for (j = 0; j < grid->res; j++) {
1087 for (k = 0; k < grid->res; k++) {
1088 hair_volume_filter_box_convolute(grid, invD, kernel_sizev, i, j, k);
1089 }
1090 }
1091 }
1092
1093 /* apply as new velocity */
1094 for (i = 0; i < size; i++) {
1095 copy_v3_v3(grid->verts[i].velocity, grid->verts[i].velocity_smooth);
1096 }
1097}
1098#endif
1099
1101 const float gmin[3],
1102 const float gmax[3])
1103{
1104 float scale;
1105 float extent[3];
1106 int resmin[3], resmax[3], res[3];
1107 float gmin_margin[3], gmax_margin[3];
1108 int size;
1109 HairGrid *grid;
1110 int i;
1111
1112 /* sanity check */
1113 if (cellsize <= 0.0f) {
1114 cellsize = 1.0f;
1115 }
1116 scale = 1.0f / cellsize;
1117
1118 sub_v3_v3v3(extent, gmax, gmin);
1119 for (i = 0; i < 3; i++) {
1120 resmin[i] = floor_int(gmin[i] * scale);
1121 resmax[i] = floor_int(gmax[i] * scale) + 1;
1122
1123 /* add margin of 1 cell */
1124 resmin[i] -= 1;
1125 resmax[i] += 1;
1126
1127 res[i] = resmax[i] - resmin[i] + 1;
1128 /* sanity check: avoid null-sized grid */
1129 if (res[i] < 4) {
1130 res[i] = 4;
1131 resmax[i] = resmin[i] + 4;
1132 }
1133 /* sanity check: avoid too large grid size */
1134 if (res[i] > MAX_HAIR_GRID_RES) {
1135 res[i] = MAX_HAIR_GRID_RES;
1136 resmax[i] = resmin[i] + MAX_HAIR_GRID_RES;
1137 }
1138
1139 gmin_margin[i] = float(resmin[i]) * cellsize;
1140 gmax_margin[i] = float(resmax[i]) * cellsize;
1141 }
1142 size = hair_grid_size(res);
1143
1144 grid = MEM_callocN<HairGrid>("hair grid");
1145 grid->res[0] = res[0];
1146 grid->res[1] = res[1];
1147 grid->res[2] = res[2];
1148 copy_v3_v3(grid->gmin, gmin_margin);
1149 copy_v3_v3(grid->gmax, gmax_margin);
1150 grid->cellsize = cellsize;
1151 grid->inv_cellsize = scale;
1152 grid->verts = MEM_calloc_arrayN<HairGridVert>(size, "hair voxel data");
1153
1154 return grid;
1155}
1156
1158{
1159 if (grid) {
1160 if (grid->verts) {
1161 MEM_freeN(grid->verts);
1162 }
1163 MEM_freeN(grid);
1164 }
1165}
1166
1168 HairGrid *grid, float *cellsize, int res[3], float gmin[3], float gmax[3])
1169{
1170 if (cellsize) {
1171 *cellsize = grid->cellsize;
1172 }
1173 if (res) {
1174 copy_v3_v3_int(res, grid->res);
1175 }
1176 if (gmin) {
1177 copy_v3_v3(gmin, grid->gmin);
1178 }
1179 if (gmax) {
1180 copy_v3_v3(gmax, grid->gmax);
1181 }
1182}
1183
1184#if 0
1185static HairGridVert *hair_volume_create_collision_grid(ClothModifierData *clmd,
1186 lfVector *lX,
1187 uint numverts)
1188{
1189 int res = hair_grid_res;
1190 int size = hair_grid_size(res);
1191 HairGridVert *collgrid;
1192 ListBase *colliders;
1193 ColliderCache *col = nullptr;
1194 float gmin[3], gmax[3], scale[3];
1195 /* 2.0f is an experimental value that seems to give good results */
1196 float collfac = 2.0f * clmd->sim_parms->collider_friction;
1197 uint v = 0;
1198 int i = 0;
1199
1200 hair_volume_get_boundbox(lX, numverts, gmin, gmax);
1201 hair_grid_get_scale(res, gmin, gmax, scale);
1202
1203 collgrid = MEM_malloc_arrayN<HairGridVert>(size, "hair collider voxel data");
1204
1205 /* initialize grid */
1206 for (i = 0; i < size; i++) {
1207 zero_v3(collgrid[i].velocity);
1208 collgrid[i].density = 0.0f;
1209 }
1210
1211 /* gather colliders */
1212 colliders = BKE_collider_cache_create(depsgraph, nullptr, nullptr);
1213 if (colliders && collfac > 0.0f) {
1214 for (col = colliders->first; col; col = col->next) {
1215 float3 *loc0 = col->collmd->x;
1216 float3 *loc1 = col->collmd->xnew;
1217 float vel[3];
1218 float weights[8];
1219 int di, dj, dk;
1220
1221 for (v = 0; v < col->collmd->numverts; v++, loc0++, loc1++) {
1222 int offset;
1223
1224 if (!hair_grid_point_valid(loc1->co, gmin, gmax)) {
1225 continue;
1226 }
1227
1228 offset = hair_grid_weights(res, gmin, scale, lX[v], weights);
1229
1230 sub_v3_v3v3(vel, loc1->co, loc0->co);
1231
1232 for (di = 0; di < 2; di++) {
1233 for (dj = 0; dj < 2; dj++) {
1234 for (dk = 0; dk < 2; dk++) {
1235 int voffset = offset + di + (dj + dk * res) * res;
1236 int iw = di + dj * 2 + dk * 4;
1237
1238 collgrid[voffset].density += weights[iw];
1239 madd_v3_v3fl(collgrid[voffset].velocity, vel, weights[iw]);
1240 }
1241 }
1242 }
1243 }
1244 }
1245 }
1246 BKE_collider_cache_free(&colliders);
1247
1248 /* divide velocity with density */
1249 for (i = 0; i < size; i++) {
1250 float density = collgrid[i].density;
1251 if (density > 0.0f) {
1252 mul_v3_fl(collgrid[i].velocity, 1.0f / density);
1253 }
1254 }
1255
1256 return collgrid;
1257}
1258#endif
void BKE_collider_cache_free(struct ListBase **colliders)
struct ListBase * BKE_collider_cache_create(struct Depsgraph *depsgraph, struct Object *self, struct Collection *collection)
#define BKE_sim_debug_data_add_dot(p, r, g, b, category,...)
Definition BKE_effect.h:238
#define BKE_sim_debug_data_add_vector(p, d, r, g, b, category,...)
Definition BKE_effect.h:258
#define BKE_sim_debug_data_add_line(p1, p2, r, g, b, category,...)
Definition BKE_effect.h:252
#define BKE_sim_debug_data_add_circle(p, radius, r, g, b, category,...)
Definition BKE_effect.h:245
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_INLINE
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3])
void sub_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
void mul_m3_fl(float R[3][3], float f)
void zero_m3(float m[3][3])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_v3_int(int r[3], const int a[3])
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
unsigned int uint
#define CLAMP_MAX(a, c)
#define CLAMP_MIN(a, b)
Read Guarded memory(de)allocation.
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define A
BPy_StructRNA * depsgraph
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
bool closest(btVector3 &v)
nullptr float
#define logf(x)
Eigen::ConjugateGradient< lMatrix, Eigen::Lower, Eigen::DiagonalPreconditioner< Scalar > > ConjugateGradient
Eigen::SparseMatrix< Scalar > lMatrix
Eigen::VectorXf lVector
Definition eigen_utils.h:92
static float verts[][3]
uint col
BLI_INLINE int hair_grid_interp_weights(const int res[3], const float gmin[3], float scale, const float vec[3], float uvw[3])
#define MARGIN_k0
#define NEIGHBOR_MARGIN_j0
#define MARGIN_i1
void SIM_hair_volume_add_segment(HairGrid *grid, const float[3], const float[3], const float x2[3], const float v2[3], const float x3[3], const float v3[3], const float[3], const float[3], const float[3], const float[3], const float[3])
#define HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, axis)
#define NEIGHBOR_MARGIN_k0
#define MARGIN_j0
void SIM_hair_volume_grid_velocity(HairGrid *grid, const float x[3], const float v[3], float fluid_factor, float r_v[3])
#define MARGIN_i0
void SIM_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])
BLI_INLINE int floor_int(float value)
#define NEIGHBOR_MARGIN_i1
#define NEIGHBOR_MARGIN_i0
BLI_INLINE int hair_grid_size(const int res[3])
static const float density_threshold
BLI_INLINE float dist_tent_v3f3(const float a[3], float x, float y, float z)
#define NEIGHBOR_MARGIN_j1
void SIM_hair_volume_grid_clear(HairGrid *grid)
#define NEIGHBOR_MARGIN_k1
BLI_INLINE void grid_to_world(HairGrid *grid, float vecw[3], const float vec[3])
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 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 float weights_sum(const float weights[8])
BLI_INLINE float floor_mod(float value)
#define MARGIN_k1
BLI_INLINE bool hair_grid_point_valid(const float vec[3], const float gmin[3], const float gmax[3])
void SIM_hair_volume_grid_geometry(HairGrid *grid, float *cellsize, int res[3], float gmin[3], float gmax[3])
void SIM_hair_volume_free_vertex_grid(HairGrid *grid)
BLI_INLINE float hair_volume_density_divergence(float density, float target_density, float strength)
#define MARGIN_j1
bool SIM_hair_volume_solve_divergence(HairGrid *grid, float, float target_density, float target_strength)
BLI_INLINE int hair_grid_offset(const float vec[3], const int res[3], const float gmin[3], float scale)
void SIM_hair_volume_add_vertex(HairGrid *grid, const float x[3], const float v[3])
HairGrid * SIM_hair_volume_create_vertex_grid(float cellsize, const float gmin[3], const float gmax[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])
void SIM_hair_volume_normalize_vertex_grid(HairGrid *grid)
void SIM_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])
#define MAX_HAIR_GRID_RES
Definition implicit.h:211
float[3] lfVector
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define B
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
#define I
#define floorf
#define fabsf
struct ClothSimSettings * sim_parms
float velocity_smooth[3]
float velocity[3]
float gmax[3]
float gmin[3]
HairGridVert * verts
float inv_cellsize
int res[3]
float cellsize
void * first
i
Definition text_draw.cc:230