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