Fluid: Enforce minimum thickness to planar flow / effector objects

Planar object now have a thickness by default. This should make it more intuitive for users as there is no need to specify an object thickness.
This commit is contained in:
Sebastián Barschkis 2020-03-23 23:50:25 +01:00
parent e9629e3cfd
commit cda81d5a4d
Notes: blender-bot 2023-02-14 09:48:25 +01:00
Referenced by issue #73161, [Mantaflow] Particles not generated on Plane object
Referenced by issue #72949, [Mantaflow] initial velocity ignored in the emission object
4 changed files with 83 additions and 78 deletions

View File

@ -361,7 +361,6 @@ def liquid_step_particles_$ID$():\n\
interpolateGrid(target=phi_sp$ID$, source=phiTmp_s$ID$)\n\
interpolateGrid(target=phiOut_sp$ID$, source=phiOut_s$ID$)\n\
\n\
flags_sp$ID$.initDomain(boundaryWidth=1 if using_fractions_s$ID$ else 0, phiWalls=phiObs_sp$ID$, outflow=boundConditions_s$ID$)\n\
setObstacleFlags(flags=flags_sp$ID$, phiObs=phiObs_sp$ID$, phiOut=None, phiIn=None) # phiIn not needed\n\
flags_sp$ID$.updateFromLevelset(levelset=phi_sp$ID$)\n\
\n\

View File

@ -194,6 +194,7 @@ class PHYSICS_PT_settings(PhysicButtonsPanel, Panel):
col = flow.column()
col.prop(domain, "clipping", text="Empty Space")
col.prop(domain, "delete_in_obstacle", text="Delete In Obstacle")
if domain.cache_type == 'MODULAR':
col.separator()
@ -272,7 +273,6 @@ class PHYSICS_PT_settings(PhysicButtonsPanel, Panel):
col.prop(effector_settings, "use_effector", text="Use Effector")
col.prop(effector_settings, "use_plane_init", text="Is Planar")
col.prop(effector_settings, "delete_in_obstacle", text="Delete In Obstacle")
if effector_settings.effector_type == 'GUIDE':
col.prop(effector_settings, "velocity_factor", text="Velocity Factor")

View File

@ -571,7 +571,7 @@ static void update_distances(int index,
BVHTreeFromMesh *tree_data,
const float ray_start[3],
float surface_thickness,
int use_plane_init);
bool use_plane_init);
static int get_light(ViewLayer *view_layer, float *light)
{
@ -1717,16 +1717,25 @@ static void update_distances(int index,
BVHTreeFromMesh *tree_data,
const float ray_start[3],
float surface_thickness,
int use_plane_init)
bool use_plane_init)
{
float min_dist = PHI_MAX;
/* a) Planar initialization */
/* Planar initialization: Find nearest cells around mesh. */
if (use_plane_init) {
BVHTreeNearest nearest = {0};
nearest.index = -1;
nearest.dist_sq = surface_thickness *
surface_thickness; /* find_nearest uses squared distance */
/* Distance between two opposing vertices in a unit cube.
* I.e. the unit cube diagonal or sqrt(3).
* This value is our nearest neighbor search distance. */
const float surface_distance = 1.732;
nearest.dist_sq = surface_distance *
surface_distance; /* find_nearest uses squared distance. */
/* Subtract optional surface thickness value and virtually increase the object size. */
if (surface_thickness) {
nearest.dist_sq += surface_thickness;
}
if (BLI_bvhtree_find_nearest(
tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) {
@ -1734,77 +1743,74 @@ static void update_distances(int index,
sub_v3_v3v3(ray, ray_start, nearest.co);
min_dist = len_v3(ray);
min_dist = (-1.0f) * fabsf(min_dist);
distance_map[index] = min_dist;
}
return;
}
/* b) Volumetric initialization: Ray-casts around mesh object. */
/* Ray-casts in 26 directions.
* (6 main axis + 12 quadrant diagonals (2D) + 8 octant diagonals (3D)). */
float ray_dirs[26][3] = {
{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f},
{0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 1.0f, 0.0f}, {1.0f, -1.0f, 0.0f},
{-1.0f, 1.0f, 0.0f}, {-1.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 1.0f}, {1.0f, 0.0f, -1.0f},
{-1.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, -1.0f}, {0.0f, 1.0f, 1.0f}, {0.0f, 1.0f, -1.0f},
{0.0f, -1.0f, 1.0f}, {0.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, -1.0f, 1.0f},
{-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, 1.0f, -1.0f}, {1.0f, -1.0f, -1.0f},
{-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}};
size_t ray_cnt = sizeof ray_dirs / sizeof ray_dirs[0];
/* Count ray mesh misses (i.e. no face hit) and cases where the ray direction matches the face
* normal direction. From this information it can be derived whether a cell is inside or outside
* the mesh. */
int miss_cnt = 0, dir_cnt = 0;
min_dist = PHI_MAX;
for (int i = 0; i < ray_cnt; i++) {
BVHTreeRayHit hit_tree = {0};
hit_tree.index = -1;
hit_tree.dist = PHI_MAX;
normalize_v3(ray_dirs[i]);
BLI_bvhtree_ray_cast(tree_data->tree,
ray_start,
ray_dirs[i],
0.0f,
&hit_tree,
tree_data->raycast_callback,
tree_data);
/* Ray did not hit mesh.
* Current point definitely not inside mesh. Inside mesh as all rays have to hit. */
if (hit_tree.index == -1) {
miss_cnt++;
/* Skip this ray since nothing was hit. */
continue;
}
/* Ray and normal are pointing in opposite directions. */
if (dot_v3v3(ray_dirs[i], hit_tree.no) <= 0) {
dir_cnt++;
}
if (hit_tree.dist < min_dist) {
min_dist = hit_tree.dist;
}
}
/* Volumetric initialization: Ray-casts around mesh object. */
else {
/* Ray-casts in 26 directions.
* (6 main axis + 12 quadrant diagonals (2D) + 8 octant diagonals (3D)). */
float ray_dirs[26][3] = {
{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f},
{0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 1.0f, 0.0f}, {1.0f, -1.0f, 0.0f},
{-1.0f, 1.0f, 0.0f}, {-1.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 1.0f}, {1.0f, 0.0f, -1.0f},
{-1.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, -1.0f}, {0.0f, 1.0f, 1.0f}, {0.0f, 1.0f, -1.0f},
{0.0f, -1.0f, 1.0f}, {0.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, -1.0f, 1.0f},
{-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, 1.0f, -1.0f}, {1.0f, -1.0f, -1.0f},
{-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}};
size_t ray_cnt = sizeof ray_dirs / sizeof ray_dirs[0];
/* Point lies inside mesh. Use negative sign for distance value.
* This "if statement" has 2 conditions that can be true for points outside mesh. */
if (!(miss_cnt > 0 || dir_cnt == ray_cnt)) {
min_dist = (-1.0f) * fabsf(min_dist);
/* Count ray mesh misses (i.e. no face hit) and cases where the ray direction matches the face
* normal direction. From this information it can be derived whether a cell is inside or
* outside the mesh. */
int miss_cnt = 0, dir_cnt = 0;
for (int i = 0; i < ray_cnt; i++) {
BVHTreeRayHit hit_tree = {0};
hit_tree.index = -1;
hit_tree.dist = PHI_MAX;
normalize_v3(ray_dirs[i]);
BLI_bvhtree_ray_cast(tree_data->tree,
ray_start,
ray_dirs[i],
0.0f,
&hit_tree,
tree_data->raycast_callback,
tree_data);
/* Ray did not hit mesh.
* Current point definitely not inside mesh. Inside mesh as all rays have to hit. */
if (hit_tree.index == -1) {
miss_cnt++;
/* Skip this ray since nothing was hit. */
continue;
}
/* Ray and normal are pointing in opposite directions. */
if (dot_v3v3(ray_dirs[i], hit_tree.no) <= 0) {
dir_cnt++;
}
if (hit_tree.dist < min_dist) {
min_dist = hit_tree.dist;
}
}
/* Point lies inside mesh. Use negative sign for distance value.
* This "if statement" has 2 conditions that can be true for points outside mesh. */
if (!(miss_cnt > 0 || dir_cnt == ray_cnt)) {
min_dist = (-1.0f) * fabsf(min_dist);
}
/* Subtract optional surface thickness value and virtually increase the object size. */
if (surface_thickness) {
min_dist -= surface_thickness;
}
}
/* Update global distance array but ensure that older entries are not overridden. */
distance_map[index] = MIN2(distance_map[index], min_dist);
/* Subtract optional surface thickness value and virtually increase the object size. */
if (surface_thickness) {
distance_map[index] -= surface_thickness;
}
/* Sanity check: Ensure that distances don't explode. */
CLAMP(distance_map[index], -PHI_MAX, PHI_MAX);
}
@ -5179,8 +5185,8 @@ void BKE_fluid_modifier_copy(const struct FluidModifierData *mmd,
tmes->surface_distance = mes->surface_distance;
tmes->type = mes->type;
tmes->flags = tmes->flags;
tmes->subframes = tmes->subframes;
tmes->flags = mes->flags;
tmes->subframes = mes->subframes;
/* guide options */
tmes->guide_mode = mes->guide_mode;

View File

@ -1332,6 +1332,11 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_flip_parts_update");
prop = RNA_def_property(srna, "delete_in_obstacle", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_DELETE_IN_OBSTACLE);
RNA_def_property_ui_text(prop, "Clear In Obstacle", "Delete fluid inside obstacles");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
/* smoke domain options */
prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE);
@ -2541,7 +2546,7 @@ static void rna_def_fluid_effector_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0, 10.0);
RNA_def_property_ui_range(prop, 0.0, 10.0, 0.05, 5);
RNA_def_property_ui_text(
prop, "Surface", "Distance around mesh surface to consider as effector");
prop, "Surface", "Additional distance around mesh surface to consider as effector");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
prop = RNA_def_property(srna, "use_plane_init", PROP_BOOLEAN, PROP_NONE);
@ -2549,11 +2554,6 @@ static void rna_def_fluid_effector_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Is Planar", "Treat this object as a planar, unclosed mesh");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
prop = RNA_def_property(srna, "delete_in_obstacle", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_DELETE_IN_OBSTACLE);
RNA_def_property_ui_text(prop, "Clear In Obstacle", "Delete fluid inside obstacles");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
prop = RNA_def_property(srna, "velocity_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "vel_multi");
RNA_def_property_range(prop, -100.0, 100.0);