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