diff options
Diffstat (limited to 'source/blender/blenkernel/intern/fluid.c')
-rw-r--r-- | source/blender/blenkernel/intern/fluid.c | 994 |
1 files changed, 542 insertions, 452 deletions
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index ae51c997a08..b75592836e0 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -36,6 +36,7 @@ #include "DNA_fluid_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" +#include "DNA_rigidbody_types.h" #include "BKE_effect.h" #include "BKE_fluid.h" @@ -80,6 +81,8 @@ # include "RE_shader_ext.h" +# include "CLG_log.h" + # include "manta_fluid_API.h" #endif /* WITH_FLUID */ @@ -95,6 +98,8 @@ static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *mmd, bool need #ifdef WITH_FLUID // #define DEBUG_PRINT +static CLG_LogRef LOG = {"bke.fluid"}; + /* -------------------------------------------------------------------- */ /** \name Fluid API * \{ */ @@ -333,11 +338,19 @@ void BKE_fluid_reallocate_copy_fluid(FluidDomainSettings *mds, manta_free(fluid_old); } +void BKE_fluid_cache_free_all(FluidDomainSettings *mds, Object *ob) +{ + int cache_map = (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE | + FLUID_DOMAIN_OUTDATED_MESH | FLUID_DOMAIN_OUTDATED_PARTICLES | + FLUID_DOMAIN_OUTDATED_GUIDE); + BKE_fluid_cache_free(mds, ob, cache_map); +} + void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map) { char temp_dir[FILE_MAX]; int flags = mds->cache_flag; - const char *relbase = modifier_path_relbase_from_global(ob); + const char *relbase = BKE_modifier_path_relbase_from_global(ob); if (cache_map & FLUID_DOMAIN_OUTDATED_DATA) { flags &= ~(FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA); @@ -478,27 +491,6 @@ static void manta_set_domain_from_mesh(FluidDomainSettings *mds, mds->cell_size[2] /= (float)mds->base_res[2]; } -static void manta_set_domain_gravity(Scene *scene, FluidDomainSettings *mds) -{ - float gravity[3] = {0.0f, 0.0f, -1.0f}; - float gravity_mag; - - /* Use global gravity if enabled. */ - if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { - copy_v3_v3(gravity, scene->physics_settings.gravity); - /* Map default value to 1.0. */ - mul_v3_fl(gravity, 1.0f / 9.810f); - - /* Convert gravity to domain space. */ - gravity_mag = len_v3(gravity); - mul_mat3_m4_v3(mds->imat, gravity); - normalize_v3(gravity); - mul_v3_fl(gravity, gravity_mag); - - copy_v3_v3(mds->gravity, gravity); - } -} - static bool BKE_fluid_modifier_init( FluidModifierData *mmd, Depsgraph *depsgraph, Object *ob, Scene *scene, Mesh *me) { @@ -509,8 +501,11 @@ static bool BKE_fluid_modifier_init( int res[3]; /* Set domain dimensions from mesh. */ manta_set_domain_from_mesh(mds, ob, me, true); - /* Set domain gravity. */ - manta_set_domain_gravity(scene, mds); + /* Set domain gravity, use global gravity if enabled. */ + if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { + copy_v3_v3(mds->gravity, scene->physics_settings.gravity); + } + mul_v3_fl(mds->gravity, mds->effector_weights->global_gravity); /* Reset domain values. */ zero_v3_int(mds->shift); zero_v3(mds->shift_f); @@ -538,7 +533,6 @@ static bool BKE_fluid_modifier_init( /* Initially dt is equal to frame length (dt can change with adaptive-time stepping though). */ mds->dt = mds->frame_length; mds->time_per_frame = 0; - mds->time_total = abs(scene_framenr - mds->cache_frame_start) * mds->frame_length; mmd->time = scene_framenr; @@ -642,6 +636,11 @@ static bool is_static_object(Object *ob) } } + /* Active rigid body objects considered to be dynamic fluid objects. */ + if (ob->rigidbody_object && ob->rigidbody_object->type == RBO_TYPE_ACTIVE) { + return false; + } + /* Finally, check if the object has animation data. If so, it is considered dynamic. */ return !BKE_object_moves_in_time(ob, true); } @@ -770,7 +769,9 @@ static void bb_combineMaps(FluidObjectBB *output, /* Values. */ output->numobjs[index_out] = bb1.numobjs[index_in]; - output->influence[index_out] = bb1.influence[index_in]; + if (output->influence && bb1.influence) { + output->influence[index_out] = bb1.influence[index_in]; + } output->distances[index_out] = bb1.distances[index_in]; if (output->velocity && bb1.velocity) { copy_v3_v3(&output->velocity[index_out * 3], &bb1.velocity[index_in * 3]); @@ -785,12 +786,14 @@ static void bb_combineMaps(FluidObjectBB *output, /* Values. */ output->numobjs[index_out] = MAX2(bb2->numobjs[index_in], output->numobjs[index_out]); - if (additive) { - output->influence[index_out] += bb2->influence[index_in] * sample_size; - } - else { - output->influence[index_out] = MAX2(bb2->influence[index_in], - output->influence[index_out]); + if (output->influence && bb2->influence) { + if (additive) { + output->influence[index_out] += bb2->influence[index_in] * sample_size; + } + else { + output->influence[index_out] = MAX2(bb2->influence[index_in], + output->influence[index_out]); + } } output->distances[index_out] = MIN2(bb2->distances[index_in], output->distances[index_out]); @@ -925,11 +928,7 @@ static void sample_effector(FluidEffectorSettings *mes, velocity_map[index * 3 + 2] += hit_vel[2]; # ifdef DEBUG_PRINT /* Debugging: Print object velocities. */ - printf("adding effector object vel: [%f, %f, %f], dx is: %f\n", - hit_vel[0], - hit_vel[1], - hit_vel[2], - mds->dx); + printf("adding effector object vel: [%f, %f, %f]\n", hit_vel[0], hit_vel[1], hit_vel[2]); # endif } } @@ -1118,6 +1117,16 @@ static void obstacles_from_mesh(Object *coll_ob, } } +static void ensure_obstaclefields(FluidDomainSettings *mds) +{ + if (mds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE) { + manta_ensure_obstacle(mds->fluid, mds->mmd); + } + if (mds->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE) { + manta_ensure_guiding(mds->fluid, mds->mmd); + } +} + static void update_obstacleflags(FluidDomainSettings *mds, Object **coll_ob_array, int coll_ob_array_len) @@ -1132,8 +1141,8 @@ static void update_obstacleflags(FluidDomainSettings *mds, /* Monitor active fields based on flow settings */ for (coll_index = 0; coll_index < coll_ob_array_len; coll_index++) { Object *coll_ob = coll_ob_array[coll_index]; - FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(coll_ob, - eModifierType_Fluid); + FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(coll_ob, + eModifierType_Fluid); /* Sanity check. */ if (!mmd2) { @@ -1145,6 +1154,10 @@ static void update_obstacleflags(FluidDomainSettings *mds, if (!mes) { break; } + if (mes->flags & FLUID_EFFECTOR_NEEDS_UPDATE) { + mes->flags &= ~FLUID_EFFECTOR_NEEDS_UPDATE; + mds->cache_flag |= FLUID_DOMAIN_OUTDATED_DATA; + } if (mes->type == FLUID_EFFECTOR_TYPE_COLLISION) { active_fields |= FLUID_DOMAIN_ACTIVE_OBSTACLE; } @@ -1153,44 +1166,56 @@ static void update_obstacleflags(FluidDomainSettings *mds, } } } - /* Finally, initialize new data fields if any */ - if (active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE) { - manta_ensure_obstacle(mds->fluid, mds->mmd); - } - if (active_fields & FLUID_DOMAIN_ACTIVE_GUIDE) { - manta_ensure_guiding(mds->fluid, mds->mmd); - } mds->active_fields = active_fields; } -static void update_obstacles(Depsgraph *depsgraph, - Scene *scene, - Object *ob, - FluidDomainSettings *mds, - float time_per_frame, - float frame_length, - int frame, - float dt) +static bool escape_effectorobject(Object *flowobj, + FluidDomainSettings *mds, + FluidEffectorSettings *mes, + int frame) { - FluidObjectBB *bb_maps = NULL; - Object **effecobjs = NULL; - uint numeffecobjs = 0, effec_index = 0; - bool is_first_frame = (frame == mds->cache_frame_start); + bool is_static = is_static_object(flowobj); - effecobjs = BKE_collision_objects_create( - depsgraph, ob, mds->effector_group, &numeffecobjs, eModifierType_Fluid); + bool use_effector = (mes->flags & FLUID_EFFECTOR_USE_EFFEC); - /* Update all effector related flags and ensure that corresponding grids get initialized. */ - update_obstacleflags(mds, effecobjs, numeffecobjs); + bool is_resume = (mds->cache_frame_pause_data == frame); + bool is_adaptive = (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN); + bool is_first_frame = (frame == mds->cache_frame_start); - /* Initialize effector maps for each flow. */ - bb_maps = MEM_callocN(sizeof(struct FluidObjectBB) * numeffecobjs, "fluid_effector_bb_maps"); + /* Cannot use static mode with adaptive domain. + * The adaptive domain might expand and only later discover the static object. */ + if (is_adaptive) { + is_static = false; + } + /* Skip flow objects with disabled inflow flag. */ + if (!use_effector) { + return true; + } + /* Skip static effector objects after initial frame. */ + if (is_static && !is_first_frame && !is_resume) { + return true; + } + return false; +} + +static void compute_obstaclesemission(Scene *scene, + FluidObjectBB *bb_maps, + struct Depsgraph *depsgraph, + float dt, + Object **effecobjs, + int frame, + float frame_length, + FluidDomainSettings *mds, + uint numeffecobjs, + float time_per_frame) +{ + bool is_first_frame = (frame == mds->cache_frame_start); /* Prepare effector maps. */ - for (effec_index = 0; effec_index < numeffecobjs; effec_index++) { + for (int effec_index = 0; effec_index < numeffecobjs; effec_index++) { Object *effecobj = effecobjs[effec_index]; - FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(effecobj, - eModifierType_Fluid); + FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(effecobj, + eModifierType_Fluid); /* Sanity check. */ if (!mmd2) { @@ -1203,69 +1228,37 @@ static void update_obstacles(Depsgraph *depsgraph, int subframes = mes->subframes; FluidObjectBB *bb = &bb_maps[effec_index]; - bool is_static = is_static_object(effecobj); - /* Cannot use static mode with adaptive domain. - * The adaptive domain might expand and only later in the simulations discover the static - * object. */ - if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { - is_static = false; - } - - /* Optimization: Static objects don't need emission computation after first frame. */ - if (is_static && !is_first_frame) { - continue; - } - /* Optimization: Skip effector objects with disabled effec flag. */ - if ((mes->flags & FLUID_EFFECTOR_USE_EFFEC) == 0) { + /* Optimization: Skip this object under certain conditions. */ + if (escape_effectorobject(effecobj, mds, mes, frame)) { continue; } - /* Length of one adaptive frame. If using adaptive stepping, length is smaller than actual - * frame length */ - float adaptframe_length = time_per_frame / frame_length; - /* Adaptive frame length as percentage */ - CLAMP(adaptframe_length, 0.0f, 1.0f); - - /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */ - float sample_size = 1.0f / (float)(subframes + 1); - /* First frame cannot have any subframes because there is (obviously) no previous frame from * where subframes could come from. */ if (is_first_frame) { subframes = 0; } - int subframe; + /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */ + float sample_size = 1.0f / (float)(subframes + 1); float subframe_dt = dt * sample_size; /* Emission loop. When not using subframes this will loop only once. */ - for (subframe = subframes; subframe >= 0; subframe--) { + for (int subframe = 0; subframe <= subframes; subframe++) { /* Temporary emission map used when subframes are enabled, i.e. at least one subframe. */ FluidObjectBB bb_temp = {NULL}; /* Set scene time */ /* Handle emission subframe */ - if (subframe > 0 && !is_first_frame) { - scene->r.subframe = adaptframe_length - - sample_size * (float)(subframe) * (dt / frame_length); + if ((subframe < subframes || time_per_frame + dt + FLT_EPSILON < frame_length) && + !is_first_frame) { + scene->r.subframe = (time_per_frame + (subframe + 1.0f) * subframe_dt) / frame_length; scene->r.cfra = frame - 1; } - /* Last frame in this loop (subframe == suframes). Can be real end frame or in between - * frames (adaptive frame). */ else { - /* Handle adaptive subframe (ie has subframe fraction). Need to set according scene - * subframe parameter. */ - if (time_per_frame < frame_length) { - scene->r.subframe = adaptframe_length; - scene->r.cfra = frame - 1; - } - /* Handle absolute endframe (ie no subframe fraction). Need to set the scene subframe - * parameter to 0 and advance current scene frame. */ - else { - scene->r.subframe = 0.0f; - scene->r.cfra = frame; - } + scene->r.subframe = 0.0f; + scene->r.cfra = frame; } /* Sanity check: subframe portion must be between 0 and 1. */ CLAMP(scene->r.subframe, 0.0f, 1.0f); @@ -1304,6 +1297,44 @@ static void update_obstacles(Depsgraph *depsgraph, } } } +} + +static void update_obstacles(Depsgraph *depsgraph, + Scene *scene, + Object *ob, + FluidDomainSettings *mds, + float time_per_frame, + float frame_length, + int frame, + float dt) +{ + FluidObjectBB *bb_maps = NULL; + Object **effecobjs = NULL; + uint numeffecobjs = 0; + bool is_resume = (mds->cache_frame_pause_data == frame); + bool is_first_frame = (frame == mds->cache_frame_start); + + effecobjs = BKE_collision_objects_create( + depsgraph, ob, mds->effector_group, &numeffecobjs, eModifierType_Fluid); + + /* Update all effector related flags and ensure that corresponding grids get initialized. */ + update_obstacleflags(mds, effecobjs, numeffecobjs); + ensure_obstaclefields(mds); + + /* Allocate effector map for each effector object. */ + bb_maps = MEM_callocN(sizeof(struct FluidObjectBB) * numeffecobjs, "fluid_effector_bb_maps"); + + /* Initialize effector map for each effector object. */ + compute_obstaclesemission(scene, + bb_maps, + depsgraph, + dt, + effecobjs, + frame, + frame_length, + mds, + numeffecobjs, + time_per_frame); float *vel_x = manta_get_ob_velocity_x(mds->fluid); float *vel_y = manta_get_ob_velocity_y(mds->fluid); @@ -1354,28 +1385,21 @@ static void update_obstacles(Depsgraph *depsgraph, } /* Prepare grids from effector objects. */ - for (effec_index = 0; effec_index < numeffecobjs; effec_index++) { + for (int effec_index = 0; effec_index < numeffecobjs; effec_index++) { Object *effecobj = effecobjs[effec_index]; - FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(effecobj, - eModifierType_Fluid); + FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(effecobj, + eModifierType_Fluid); /* Sanity check. */ if (!mmd2) { continue; } - bool is_static = is_static_object(effecobj); /* Cannot use static mode with adaptive domain. * The adaptive domain might expand and only later in the simulations discover the static * object. */ - if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { - is_static = false; - } - - /* Optimization: Static objects don't need emission application after first frame. */ - if (is_static && !is_first_frame) { - continue; - } + bool is_static = is_static_object(effecobj) && + ((mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) == 0); /* Check for initialized effector object. */ if ((mmd2->type & MOD_FLUID_TYPE_EFFEC) && mmd2->effector) { @@ -1415,53 +1439,35 @@ static void update_obstacles(Depsgraph *depsgraph, continue; } - /* Apply static effectors to obstacle grid. */ - if (is_static && is_first_frame) { - if (mes->type == FLUID_EFFECTOR_TYPE_COLLISION) { - apply_effector_fields(mes, - d_index, - distance_map[e_index], - phi_obsstatic_in, - numobjs_map[e_index], - num_obstacles, - 0.0f, - NULL, - 0.0f, - NULL, - 0.0f, - NULL); - } + if (mes->type == FLUID_EFFECTOR_TYPE_COLLISION) { + float *levelset = ((is_first_frame || is_resume) && is_static) ? phi_obsstatic_in : + phi_obs_in; + apply_effector_fields(mes, + d_index, + distance_map[e_index], + levelset, + numobjs_map[e_index], + num_obstacles, + velocity_map[e_index * 3], + vel_x, + velocity_map[e_index * 3 + 1], + vel_y, + velocity_map[e_index * 3 + 2], + vel_z); } - /* Apply moving effectors to obstacle grid. */ - else if (!is_static) { - if (mes->type == FLUID_EFFECTOR_TYPE_COLLISION) { - apply_effector_fields(mes, - d_index, - distance_map[e_index], - phi_obs_in, - numobjs_map[e_index], - num_obstacles, - velocity_map[e_index * 3], - vel_x, - velocity_map[e_index * 3 + 1], - vel_y, - velocity_map[e_index * 3 + 2], - vel_z); - } - if (mes->type == FLUID_EFFECTOR_TYPE_GUIDE) { - apply_effector_fields(mes, - d_index, - distance_map[e_index], - phi_guide_in, - numobjs_map[e_index], - num_guides, - velocity_map[e_index * 3], - vel_x_guide, - velocity_map[e_index * 3 + 1], - vel_y_guide, - velocity_map[e_index * 3 + 2], - vel_z_guide); - } + if (mes->type == FLUID_EFFECTOR_TYPE_GUIDE) { + apply_effector_fields(mes, + d_index, + distance_map[e_index], + phi_guide_in, + numobjs_map[e_index], + num_guides, + velocity_map[e_index * 3], + vel_x_guide, + velocity_map[e_index * 3 + 1], + vel_y_guide, + velocity_map[e_index * 3 + 2], + vel_z_guide); } } } @@ -1966,9 +1972,9 @@ static void sample_mesh(FluidFlowSettings *mfs, normalize_v3(hit_normal); /* Apply normal directional velocity. */ - velocity_map[index * 3] += hit_normal[0] * mfs->vel_normal * 0.25f; - velocity_map[index * 3 + 1] += hit_normal[1] * mfs->vel_normal * 0.25f; - velocity_map[index * 3 + 2] += hit_normal[2] * mfs->vel_normal * 0.25f; + velocity_map[index * 3] += hit_normal[0] * mfs->vel_normal; + velocity_map[index * 3 + 1] += hit_normal[1] * mfs->vel_normal; + velocity_map[index * 3 + 2] += hit_normal[2] * mfs->vel_normal; } /* Apply object velocity. */ if (has_velocity && mfs->vel_multi) { @@ -2458,12 +2464,13 @@ BLI_INLINE void apply_outflow_fields(int index, float *color_b, float *phiout) { - /* determine outflow cells - phiout used in smoke and liquids */ + /* Set levelset value for liquid inflow. + * Ensure that distance value is "joined" into the levelset. */ if (phiout) { - phiout[index] = distance_value; + phiout[index] = MIN2(distance_value, phiout[index]); } - /* set smoke outflow */ + /* Set smoke outflow, i.e. reset cell to zero. */ if (density) { density[index] = 0.0f; } @@ -2581,6 +2588,32 @@ BLI_INLINE void apply_inflow_fields(FluidFlowSettings *mfs, } } +static void ensure_flowsfields(FluidDomainSettings *mds) +{ + if (mds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL) { + manta_ensure_invelocity(mds->fluid, mds->mmd); + } + if (mds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW) { + manta_ensure_outflow(mds->fluid, mds->mmd); + } + if (mds->active_fields & FLUID_DOMAIN_ACTIVE_HEAT) { + manta_smoke_ensure_heat(mds->fluid, mds->mmd); + } + if (mds->active_fields & FLUID_DOMAIN_ACTIVE_FIRE) { + manta_smoke_ensure_fire(mds->fluid, mds->mmd); + } + if (mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) { + /* initialize all smoke with "active_color" */ + manta_smoke_ensure_colors(mds->fluid, mds->mmd); + } + if (mds->type == FLUID_DOMAIN_TYPE_LIQUID && + (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY || + mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM || + mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER)) { + manta_liquid_ensure_sndparts(mds->fluid, mds->mmd); + } +} + static void update_flowsflags(FluidDomainSettings *mds, Object **flowobjs, int numflowobj) { int active_fields = mds->active_fields; @@ -2588,15 +2621,14 @@ static void update_flowsflags(FluidDomainSettings *mds, Object **flowobjs, int n /* First, remove all flags that we want to update. */ int prev_flags = (FLUID_DOMAIN_ACTIVE_INVEL | FLUID_DOMAIN_ACTIVE_OUTFLOW | - FLUID_DOMAIN_ACTIVE_HEAT | FLUID_DOMAIN_ACTIVE_FIRE | - FLUID_DOMAIN_ACTIVE_COLOR_SET | FLUID_DOMAIN_ACTIVE_COLORS); + FLUID_DOMAIN_ACTIVE_HEAT | FLUID_DOMAIN_ACTIVE_FIRE); active_fields &= ~prev_flags; /* Monitor active fields based on flow settings */ for (flow_index = 0; flow_index < numflowobj; flow_index++) { - Object *coll_ob = flowobjs[flow_index]; - FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(coll_ob, - eModifierType_Fluid); + Object *flow_ob = flowobjs[flow_index]; + FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(flow_ob, + eModifierType_Fluid); /* Sanity check. */ if (!mmd2) { @@ -2608,6 +2640,10 @@ static void update_flowsflags(FluidDomainSettings *mds, Object **flowobjs, int n if (!mfs) { break; } + if (mfs->flags & FLUID_FLOW_NEEDS_UPDATE) { + mfs->flags &= ~FLUID_FLOW_NEEDS_UPDATE; + mds->cache_flag |= FLUID_DOMAIN_OUTDATED_DATA; + } if (mfs->flags & FLUID_FLOW_INITVELOCITY) { active_fields |= FLUID_DOMAIN_ACTIVE_INVEL; } @@ -2656,60 +2692,74 @@ static void update_flowsflags(FluidDomainSettings *mds, Object **flowobjs, int n active_fields |= FLUID_DOMAIN_ACTIVE_COLORS; } } - /* Finally, initialize new data fields if any */ - if (active_fields & FLUID_DOMAIN_ACTIVE_INVEL) { - manta_ensure_invelocity(mds->fluid, mds->mmd); - } - if (active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW) { - manta_ensure_outflow(mds->fluid, mds->mmd); - } - if (active_fields & FLUID_DOMAIN_ACTIVE_HEAT) { - manta_smoke_ensure_heat(mds->fluid, mds->mmd); + mds->active_fields = active_fields; +} + +static bool escape_flowsobject(Object *flowobj, + FluidDomainSettings *mds, + FluidFlowSettings *mfs, + int frame) +{ + bool use_velocity = (mfs->flags & FLUID_FLOW_INITVELOCITY); + bool is_static = is_static_object(flowobj); + + bool liquid_flow = mfs->type == FLUID_FLOW_TYPE_LIQUID; + bool gas_flow = (mfs->type == FLUID_FLOW_TYPE_SMOKE || mfs->type == FLUID_FLOW_TYPE_FIRE || + mfs->type == FLUID_FLOW_TYPE_SMOKEFIRE); + bool is_geometry = (mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY); + bool is_inflow = (mfs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW); + bool is_outflow = (mfs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW); + bool use_flow = (mfs->flags & FLUID_FLOW_USE_INFLOW); + + bool liquid_domain = mds->type == FLUID_DOMAIN_TYPE_LIQUID; + bool gas_domain = mds->type == FLUID_DOMAIN_TYPE_GAS; + bool is_adaptive = (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN); + bool is_resume = (mds->cache_frame_pause_data == frame); + bool is_first_frame = (mds->cache_frame_start == frame); + + /* Cannot use static mode with adaptive domain. + * The adaptive domain might expand and only later discover the static object. */ + if (is_adaptive) { + is_static = false; + } + /* Skip flow objects with disabled inflow flag. */ + if ((is_inflow || is_outflow) && !use_flow) { + return true; } - if (active_fields & FLUID_DOMAIN_ACTIVE_FIRE) { - manta_smoke_ensure_fire(mds->fluid, mds->mmd); + /* No need to compute emission value if it won't be applied. */ + if (liquid_flow && is_geometry && !is_first_frame) { + return true; } - if (active_fields & FLUID_DOMAIN_ACTIVE_COLORS) { - /* initialize all smoke with "active_color" */ - manta_smoke_ensure_colors(mds->fluid, mds->mmd); + /* Skip flow object if it does not "belong" to this domain type. */ + if ((liquid_flow && gas_domain) || (gas_flow && liquid_domain)) { + return true; } - if (mds->type == FLUID_DOMAIN_TYPE_LIQUID && - (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY || - mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM || - mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER)) { - manta_liquid_ensure_sndparts(mds->fluid, mds->mmd); + /* Optimization: Static liquid flow objects don't need emission after first frame. + * TODO (sebbas): Also do not use static mode if initial velocities are enabled. */ + if (liquid_flow && is_static && !is_first_frame && !is_resume && !use_velocity) { + return true; } - mds->active_fields = active_fields; + return false; } -static void update_flowsfluids(struct Depsgraph *depsgraph, - Scene *scene, - Object *ob, - FluidDomainSettings *mds, - float time_per_frame, - float frame_length, - int frame, - float dt) +static void compute_flowsemission(Scene *scene, + FluidObjectBB *bb_maps, + struct Depsgraph *depsgraph, + float dt, + Object **flowobjs, + int frame, + float frame_length, + FluidDomainSettings *mds, + uint numflowobjs, + float time_per_frame) { - FluidObjectBB *bb_maps = NULL; - Object **flowobjs = NULL; - uint numflowobj = 0, flow_index = 0; bool is_first_frame = (frame == mds->cache_frame_start); - flowobjs = BKE_collision_objects_create( - depsgraph, ob, mds->fluid_group, &numflowobj, eModifierType_Fluid); - - /* Update all flow related flags and ensure that corresponding grids get initialized. */ - update_flowsflags(mds, flowobjs, numflowobj); - - /* Initialize emission maps for each flow. */ - bb_maps = MEM_callocN(sizeof(struct FluidObjectBB) * numflowobj, "fluid_flow_bb_maps"); - /* Prepare flow emission maps. */ - for (flow_index = 0; flow_index < numflowobj; flow_index++) { + for (int flow_index = 0; flow_index < numflowobjs; flow_index++) { Object *flowobj = flowobjs[flow_index]; - FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(flowobj, - eModifierType_Fluid); + FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(flowobj, + eModifierType_Fluid); /* Sanity check. */ if (!mmd2) { @@ -2722,48 +2772,10 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, int subframes = mfs->subframes; FluidObjectBB *bb = &bb_maps[flow_index]; - bool use_velocity = mfs->flags & FLUID_FLOW_INITVELOCITY; - bool is_static = is_static_object(flowobj); - /* Cannot use static mode with adaptive domain. - * The adaptive domain might expand and only later in the simulations discover the static - * object. */ - if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { - is_static = false; - } - - /* Optimization: Skip flow objects with disabled inflow flag. */ - if (mfs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW && - (mfs->flags & FLUID_FLOW_USE_INFLOW) == 0) { - continue; - } - /* Optimization: No need to compute emission value if it won't be applied. */ - if (mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY && !is_first_frame) { - continue; - } - /* Optimization: Skip flow object if it does not "belong" to this domain type. */ - if (mfs->type == FLUID_FLOW_TYPE_LIQUID && mds->type == FLUID_DOMAIN_TYPE_GAS) { - continue; - } - if ((mfs->type == FLUID_FLOW_TYPE_SMOKE || mfs->type == FLUID_FLOW_TYPE_FIRE || - mfs->type == FLUID_FLOW_TYPE_SMOKEFIRE) && - mds->type == FLUID_DOMAIN_TYPE_LIQUID) { + /* Optimization: Skip this object under certain conditions. */ + if (escape_flowsobject(flowobj, mds, mfs, frame)) { continue; } - /* Optimization: Static liquid flow objects don't need emission computation after first - * frame. - * TODO (sebbas): Also do not use static mode if initial velocities are enabled. */ - if (mfs->type == FLUID_FLOW_TYPE_LIQUID && is_static && !is_first_frame && !use_velocity) { - continue; - } - - /* Length of one adaptive frame. If using adaptive stepping, length is smaller than actual - * frame length */ - float adaptframe_length = time_per_frame / frame_length; - /* Adaptive frame length as percentage */ - CLAMP(adaptframe_length, 0.0f, 1.0f); - - /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */ - float sample_size = 1.0f / (float)(subframes + 1); /* First frame cannot have any subframes because there is (obviously) no previous frame from * where subframes could come from. */ @@ -2771,38 +2783,26 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, subframes = 0; } - int subframe; + /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */ + float sample_size = 1.0f / (float)(subframes + 1); float subframe_dt = dt * sample_size; /* Emission loop. When not using subframes this will loop only once. */ - for (subframe = subframes; subframe >= 0; subframe--) { - + for (int subframe = 0; subframe <= subframes; subframe++) { /* Temporary emission map used when subframes are enabled, i.e. at least one subframe. */ FluidObjectBB bb_temp = {NULL}; /* Set scene time */ - /* Handle emission subframe */ - if (subframe > 0 && !is_first_frame) { - scene->r.subframe = adaptframe_length - - sample_size * (float)(subframe) * (dt / frame_length); + if ((subframe < subframes || time_per_frame + dt + FLT_EPSILON < frame_length) && + !is_first_frame) { + scene->r.subframe = (time_per_frame + (subframe + 1.0f) * subframe_dt) / frame_length; scene->r.cfra = frame - 1; } - /* Last frame in this loop (subframe == suframes). Can be real end frame or in between - * frames (adaptive frame). */ else { - /* Handle adaptive subframe (ie has subframe fraction). Need to set according scene - * subframe parameter. */ - if (time_per_frame < frame_length) { - scene->r.subframe = adaptframe_length; - scene->r.cfra = frame - 1; - } - /* Handle absolute endframe (ie no subframe fraction). Need to set the scene subframe - * parameter to 0 and advance current scene frame. */ - else { - scene->r.subframe = 0.0f; - scene->r.cfra = frame; - } + scene->r.subframe = 0.0f; + scene->r.cfra = frame; } + /* Sanity check: subframe portion must be between 0 and 1. */ CLAMP(scene->r.subframe, 0.0f, 1.0f); # ifdef DEBUG_PRINT @@ -2862,15 +2862,55 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, frame_length, dt); # endif +} + +static void update_flowsfluids(struct Depsgraph *depsgraph, + Scene *scene, + Object *ob, + FluidDomainSettings *mds, + float time_per_frame, + float frame_length, + int frame, + float dt) +{ + FluidObjectBB *bb_maps = NULL; + Object **flowobjs = NULL; + uint numflowobjs = 0; + bool is_resume = (mds->cache_frame_pause_data == frame); + bool is_first_frame = (mds->cache_frame_start == frame); + + flowobjs = BKE_collision_objects_create( + depsgraph, ob, mds->fluid_group, &numflowobjs, eModifierType_Fluid); + + /* Update all flow related flags and ensure that corresponding grids get initialized. */ + update_flowsflags(mds, flowobjs, numflowobjs); + ensure_flowsfields(mds); + + /* Allocate emission map for each flow object. */ + bb_maps = MEM_callocN(sizeof(struct FluidObjectBB) * numflowobjs, "fluid_flow_bb_maps"); + + /* Initialize emission map for each flow object. */ + compute_flowsemission(scene, + bb_maps, + depsgraph, + dt, + flowobjs, + frame, + frame_length, + mds, + numflowobjs, + time_per_frame); /* Adjust domain size if needed. Only do this once for every frame. */ if (mds->type == FLUID_DOMAIN_TYPE_GAS && mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { - adaptive_domain_adjust(mds, ob, bb_maps, numflowobj, dt); + adaptive_domain_adjust(mds, ob, bb_maps, numflowobjs, dt); } float *phi_in = manta_get_phi_in(mds->fluid); float *phistatic_in = manta_get_phistatic_in(mds->fluid); float *phiout_in = manta_get_phiout_in(mds->fluid); + float *phioutstatic_in = manta_get_phioutstatic_in(mds->fluid); + float *density = manta_smoke_get_density(mds->fluid); float *color_r = manta_smoke_get_color_r(mds->fluid); float *color_g = manta_smoke_get_color_g(mds->fluid); @@ -2893,16 +2933,18 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, float *velz_initial = manta_get_in_velocity_z(mds->fluid); uint z; - bool use_adaptivedomain = (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN); - /* Grid reset before writing again. */ for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) { + /* Only reset static phi on first frame, dynamic phi gets reset every time. */ + if (phistatic_in && is_first_frame) { + phistatic_in[z] = PHI_MAX; + } if (phi_in) { phi_in[z] = PHI_MAX; } - /* Only reset static inflow on first frame. Only use static inflow without adaptive domains. */ - if (phistatic_in && (is_first_frame || use_adaptivedomain)) { - phistatic_in[z] = PHI_MAX; + /* Only reset static phi on first frame, dynamic phi gets reset every time. */ + if (phioutstatic_in && is_first_frame) { + phioutstatic_in[z] = PHI_MAX; } if (phiout_in) { phiout_in[z] = PHI_MAX; @@ -2934,10 +2976,10 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, } /* Apply emission data for every flow object. */ - for (flow_index = 0; flow_index < numflowobj; flow_index++) { + for (int flow_index = 0; flow_index < numflowobjs; flow_index++) { Object *flowobj = flowobjs[flow_index]; - FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(flowobj, - eModifierType_Fluid); + FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(flowobj, + eModifierType_Fluid); /* Sanity check. */ if (!mmd2) { @@ -2948,38 +2990,11 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, if ((mmd2->type & MOD_FLUID_TYPE_FLOW) && mmd2->flow) { FluidFlowSettings *mfs = mmd2->flow; - bool use_velocity = mfs->flags & FLUID_FLOW_INITVELOCITY; - bool use_inflow = (mfs->flags & FLUID_FLOW_USE_INFLOW); - bool is_liquid = (mfs->type == FLUID_FLOW_TYPE_LIQUID); bool is_inflow = (mfs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW); bool is_geometry = (mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY); bool is_outflow = (mfs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW); - - bool is_static = is_static_object(flowobj); - /* Cannot use static mode with adaptive domain. - * The adaptive domain might expand and only later in the simulations discover the static - * object. */ - if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { - is_static = false; - } - - /* Optimization: Skip flow objects with disabled flow flag. */ - if (is_inflow && !use_inflow) { - continue; - } - /* Optimization: Liquid objects don't always need emission application after first frame. */ - if (is_liquid && !is_first_frame) { - - /* Skip static liquid objects that are not on the first frame. - * TODO (sebbas): Also do not use static mode if initial velocities are enabled. */ - if (is_static && !use_velocity) { - continue; - } - /* Liquid geometry objects don't need emission application after first frame. */ - if (is_geometry) { - continue; - } - } + bool is_static = is_static_object(flowobj) && + ((mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) == 0); FluidObjectBB *bb = &bb_maps[flow_index]; float *velocity_map = bb->velocity; @@ -3012,6 +3027,8 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, /* Delete fluid in outflow regions. */ if (is_outflow) { + float *levelset = ((is_first_frame || is_resume) && is_static) ? phioutstatic_in : + phiout_in; apply_outflow_fields(d_index, distance_map[e_index], density_in, @@ -3021,7 +3038,7 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, color_r_in, color_g_in, color_b_in, - phiout_in); + levelset); } /* Do not apply inflow after the first frame when in geometry mode. */ else if (is_geometry && !is_first_frame) { @@ -3046,31 +3063,11 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, phi_in, emission_in); } - /* Static liquid objects need inflow application onto static phi grid. */ - else if (is_inflow && is_liquid && is_static && is_first_frame) { - apply_inflow_fields(mfs, - 0.0f, - distance_map[e_index], - d_index, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - phistatic_in, - NULL); - } /* Main inflow application. */ else if (is_geometry || is_inflow) { + float *levelset = ((is_first_frame || is_resume) && is_static && !is_geometry) ? + phistatic_in : + phi_in; apply_inflow_fields(mfs, emission_map[e_index], distance_map[e_index], @@ -3089,12 +3086,22 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, color_g, color_b_in, color_b, - phi_in, + levelset, emission_in); if (mfs->flags & FLUID_FLOW_INITVELOCITY) { - velx_initial[d_index] = velocity_map[e_index * 3]; - vely_initial[d_index] = velocity_map[e_index * 3 + 1]; - velz_initial[d_index] = velocity_map[e_index * 3 + 2]; + /* Use the initial velocity from the inflow object with the highest velocity for + * now. */ + float vel_initial[3]; + vel_initial[0] = velx_initial[d_index]; + vel_initial[1] = vely_initial[d_index]; + vel_initial[2] = velz_initial[d_index]; + float vel_initial_strength = len_squared_v3(vel_initial); + float vel_map_strength = len_squared_v3(velocity_map + 3 * e_index); + if (vel_map_strength > vel_initial_strength) { + velx_initial[d_index] = velocity_map[e_index * 3]; + vely_initial[d_index] = velocity_map[e_index * 3 + 1]; + velz_initial[d_index] = velocity_map[e_index * 3 + 2]; + } } } } @@ -3189,7 +3196,7 @@ static void update_effectors( { ListBase *effectors; /* make sure smoke flow influence is 0.0f */ - mds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f; + mds->effector_weights->weight[PFIELD_FLUIDFLOW] = 0.0f; effectors = BKE_effectors_create(depsgraph, ob, NULL, mds->effector_weights); if (effectors) { @@ -3299,6 +3306,16 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Obj /* Biggest dimension will be used for upscaling. */ float max_size = MAX3(size[0], size[1], size[2]); + float co_scale[3]; + co_scale[0] = max_size / ob->scale[0]; + co_scale[1] = max_size / ob->scale[1]; + co_scale[2] = max_size / ob->scale[2]; + + float co_offset[3]; + co_offset[0] = (mds->p0[0] + mds->p1[0]) / 2.0f; + co_offset[1] = (mds->p0[1] + mds->p1[1]) / 2.0f; + co_offset[2] = (mds->p0[2] + mds->p1[2]) / 2.0f; + /* Normals. */ normals = MEM_callocN(sizeof(short) * num_normals * 3, "Fluidmesh_tmp_normals"); @@ -3322,9 +3339,9 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Obj mverts->co[2] *= mds->dx / mds->mesh_scale; } - mverts->co[0] *= max_size / fabsf(ob->scale[0]); - mverts->co[1] *= max_size / fabsf(ob->scale[1]); - mverts->co[2] *= max_size / fabsf(ob->scale[2]); + mul_v3_v3(mverts->co, co_scale); + add_v3_v3(mverts->co, co_offset); + # ifdef DEBUG_PRINT /* Debugging: Print coordinates of vertices. */ printf("mverts->co[0]: %f, mverts->co[1]: %f, mverts->co[2]: %f\n", @@ -3539,7 +3556,7 @@ static int manta_step( Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me, FluidModifierData *mmd, int frame) { FluidDomainSettings *mds = mmd->domain; - float dt, frame_length, time_total; + float dt, frame_length, time_total, time_total_old; float time_per_frame; bool init_resolution = true; @@ -3563,6 +3580,8 @@ static int manta_step( dt = mds->dt; time_per_frame = 0; time_total = mds->time_total; + /* Keep track of original total time to correct small errors at end of step. */ + time_total_old = mds->time_total; BLI_mutex_lock(&object_update_lock); @@ -3595,6 +3614,7 @@ static int manta_step( break; } + /* Only bake if the domain is bigger than one cell (important for adaptive domain). */ if (mds->total_cells > 1) { update_effectors(depsgraph, scene, ob, mds, dt); manta_bake_data(mds->fluid, mmd, frame); @@ -3606,15 +3626,11 @@ static int manta_step( mds->time_per_frame = time_per_frame; mds->time_total = time_total; - - /* If user requested stop, quit baking */ - if (G.is_break && !mode_replay) { - result = 0; - break; - } } + /* Total time must not exceed framecount times framelength. Correct tiny errors here. */ + CLAMP(mds->time_total, mds->time_total, time_total_old + mds->frame_length); - if (mds->type == FLUID_DOMAIN_TYPE_GAS) { + if (mds->type == FLUID_DOMAIN_TYPE_GAS && result) { manta_smoke_calc_transparency(mds, DEG_get_evaluated_view_layer(depsgraph)); } BLI_mutex_unlock(&object_update_lock); @@ -3704,24 +3720,60 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, uint numobj = 0; FluidModifierData *mmd_parent = NULL; - bool is_startframe; + bool is_startframe, has_advanced; is_startframe = (scene_framenr == mds->cache_frame_start); + has_advanced = (scene_framenr == mmd->time + 1); - /* Reset fluid if no fluid present. */ + /* Do not process modifier if current frame is out of cache range. */ + if (scene_framenr < mds->cache_frame_start || scene_framenr > mds->cache_frame_end) { + return; + } + + /* Reset fluid if no fluid present. Also resets active fields. */ if (!mds->fluid) { BKE_fluid_modifier_reset_ex(mmd, false); + } - /* Fluid domain init must not fail in order to continue modifier evaluation. */ - if (!BKE_fluid_modifier_init(mmd, depsgraph, ob, scene, me)) { - return; - } + /* Ensure cache directory is not relative. */ + const char *relbase = BKE_modifier_path_relbase_from_global(ob); + BLI_path_abs(mds->cache_directory, relbase); + + /* Ensure that all flags are up to date before doing any baking and/or cache reading. */ + objs = BKE_collision_objects_create( + depsgraph, ob, mds->fluid_group, &numobj, eModifierType_Fluid); + update_flowsflags(mds, objs, numobj); + if (objs) { + MEM_freeN(objs); + } + objs = BKE_collision_objects_create( + depsgraph, ob, mds->effector_group, &numobj, eModifierType_Fluid); + update_obstacleflags(mds, objs, numobj); + if (objs) { + MEM_freeN(objs); + } + + /* TODO (sebbas): Cache reset for when flow / effector object need update flag is set. */ +# if 0 + /* If the just updated flags now carry the 'outdated' flag, reset the cache here! + * Plus sanity check: Do not clear cache on file load. */ + if (mds->cache_flag & FLUID_DOMAIN_OUTDATED_DATA && + ((mds->flags & FLUID_DOMAIN_FILE_LOAD) == 0)) { + BKE_fluid_cache_free_all(mds, ob); + BKE_fluid_modifier_reset_ex(mmd, false); + } +# endif + + /* Fluid domain init must not fail in order to continue modifier evaluation. */ + if (!mds->fluid && !BKE_fluid_modifier_init(mmd, depsgraph, ob, scene, me)) { + CLOG_ERROR(&LOG, "Fluid initialization failed. Should not happen!"); + return; } BLI_assert(mds->fluid); /* Guiding parent res pointer needs initialization. */ guide_parent = mds->guide_parent; if (guide_parent) { - mmd_parent = (FluidModifierData *)modifiers_findByType(guide_parent, eModifierType_Fluid); + mmd_parent = (FluidModifierData *)BKE_modifiers_findby_type(guide_parent, eModifierType_Fluid); if (mmd_parent && mmd_parent->domain) { copy_v3_v3_int(mds->guide_res, mmd_parent->domain->res); } @@ -3732,26 +3784,17 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, mds->frame_length = DT_DEFAULT * (25.0f / fps) * mds->time_scale; mds->dt = mds->frame_length; mds->time_per_frame = 0; - /* Get distance between cache start and current frame for total time. */ - mds->time_total = abs(scene_framenr - mds->cache_frame_start) * mds->frame_length; - - objs = BKE_collision_objects_create( - depsgraph, ob, mds->fluid_group, &numobj, eModifierType_Fluid); - update_flowsflags(mds, objs, numobj); - if (objs) { - MEM_freeN(objs); - } - objs = BKE_collision_objects_create( - depsgraph, ob, mds->effector_group, &numobj, eModifierType_Fluid); - update_obstacleflags(mds, objs, numobj); - if (objs) { - MEM_freeN(objs); + /* Ensure that gravity is copied over every frame (could be keyframed). */ + if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { + copy_v3_v3(mds->gravity, scene->physics_settings.gravity); + mul_v3_fl(mds->gravity, mds->effector_weights->global_gravity); } - /* Ensure cache directory is not relative. */ - const char *relbase = modifier_path_relbase_from_global(ob); - BLI_path_abs(mds->cache_directory, relbase); + int next_frame = scene_framenr + 1; + int prev_frame = scene_framenr - 1; + /* Ensure positivity of previous frame. */ + CLAMP(prev_frame, mds->cache_frame_start, prev_frame); int data_frame = scene_framenr, noise_frame = scene_framenr; int mesh_frame = scene_framenr, particles_frame = scene_framenr, guide_frame = scene_framenr; @@ -3773,18 +3816,20 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, with_guide = mds->flags & FLUID_DOMAIN_USE_GUIDE; with_particles = drops || bubble || floater; - bool has_data, has_noise, has_mesh, has_particles, has_guide; - has_data = has_noise = has_mesh = has_particles = has_guide = false; + bool has_data, has_noise, has_mesh, has_particles, has_guide, has_config; + has_data = manta_has_data(mds->fluid, mmd, scene_framenr); + has_noise = manta_has_noise(mds->fluid, mmd, scene_framenr); + has_mesh = manta_has_mesh(mds->fluid, mmd, scene_framenr); + has_particles = manta_has_particles(mds->fluid, mmd, scene_framenr); + has_guide = manta_has_guiding(mds->fluid, mmd, scene_framenr, guide_parent); + has_config = false; - bool baking_data, baking_noise, baking_mesh, baking_particles, baking_guide, bake_outdated; + bool baking_data, baking_noise, baking_mesh, baking_particles, baking_guide; baking_data = mds->cache_flag & FLUID_DOMAIN_BAKING_DATA; baking_noise = mds->cache_flag & FLUID_DOMAIN_BAKING_NOISE; baking_mesh = mds->cache_flag & FLUID_DOMAIN_BAKING_MESH; baking_particles = mds->cache_flag & FLUID_DOMAIN_BAKING_PARTICLES; baking_guide = mds->cache_flag & FLUID_DOMAIN_BAKING_GUIDE; - bake_outdated = mds->cache_flag & (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE | - FLUID_DOMAIN_OUTDATED_MESH | FLUID_DOMAIN_OUTDATED_PARTICLES | - FLUID_DOMAIN_OUTDATED_GUIDE); bool resume_data, resume_noise, resume_mesh, resume_particles, resume_guide; resume_data = (!is_startframe) && (mds->cache_frame_pause_data == scene_framenr); @@ -3797,15 +3842,28 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, read_cache = false; bake_cache = baking_data || baking_noise || baking_mesh || baking_particles || baking_guide; + bool next_data, next_noise, next_mesh, next_particles, next_guide; + next_data = manta_has_data(mds->fluid, mmd, next_frame); + next_noise = manta_has_noise(mds->fluid, mmd, next_frame); + next_mesh = manta_has_mesh(mds->fluid, mmd, next_frame); + next_particles = manta_has_particles(mds->fluid, mmd, next_frame); + next_guide = manta_has_guiding(mds->fluid, mmd, next_frame, guide_parent); + + bool prev_data, prev_noise, prev_mesh, prev_particles, prev_guide; + prev_data = manta_has_data(mds->fluid, mmd, prev_frame); + prev_noise = manta_has_noise(mds->fluid, mmd, prev_frame); + prev_mesh = manta_has_mesh(mds->fluid, mmd, prev_frame); + prev_particles = manta_has_particles(mds->fluid, mmd, prev_frame); + prev_guide = manta_has_guiding(mds->fluid, mmd, prev_frame, guide_parent); + + /* Unused for now. */ + UNUSED_VARS(has_guide, prev_guide, next_mesh, next_guide); + bool with_gdomain; with_gdomain = (mds->guide_source == FLUID_DOMAIN_GUIDE_SRC_DOMAIN); int o_res[3], o_min[3], o_max[3], o_shift[3]; int mode = mds->cache_type; - int prev_frame = scene_framenr - 1; - - /* Ensure positivity of previous frame. */ - CLAMP(prev_frame, 1, prev_frame); /* Cache mode specific settings. */ switch (mode) { @@ -3853,32 +3911,39 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, break; case FLUID_DOMAIN_CACHE_REPLAY: default: + baking_data = !has_data && (is_startframe || prev_data); + if (with_smoke && with_noise) { + baking_noise = !has_noise && (is_startframe || prev_noise); + } + if (with_liquid && with_mesh) { + baking_mesh = !has_mesh && (is_startframe || prev_mesh); + } + if (with_liquid && with_particles) { + baking_particles = !has_particles && (is_startframe || prev_particles); + } + /* Always trying to read the cache in replay mode. */ read_cache = true; + bake_cache = false; break; } - /* Cache outdated? If so reset, don't read, and then just rebake. - * Note: Only do this in replay mode! */ - bool mode_replay = (mode == FLUID_DOMAIN_CACHE_REPLAY); - if (bake_outdated && mode_replay) { - read_cache = false; - bake_cache = true; - BKE_fluid_cache_free(mds, ob, mds->cache_flag); - } - /* Try to read from cache and keep track of read success. */ if (read_cache) { /* Read mesh cache. */ if (with_liquid && with_mesh) { + has_config = manta_read_config(mds->fluid, mmd, mesh_frame); + /* Update mesh data from file is faster than via Python (manta_read_mesh()). */ has_mesh = manta_update_mesh_structures(mds->fluid, mmd, mesh_frame); } /* Read particles cache. */ if (with_liquid && with_particles) { - if (!baking_data && !baking_particles && !mode_replay) { + has_config = manta_read_config(mds->fluid, mmd, particles_frame); + + if (!baking_data && !baking_particles && next_particles) { /* Update particle data from file is faster than via Python (manta_read_particles()). */ has_particles = manta_update_particle_structures(mds->fluid, mmd, particles_frame); } @@ -3895,15 +3960,15 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, /* Read noise and data cache */ if (with_smoke && with_noise) { + has_config = manta_read_config(mds->fluid, mmd, noise_frame); /* Only reallocate when just reading cache or when resuming during bake. */ - if ((!baking_noise || (baking_noise && resume_noise)) && - manta_read_config(mds->fluid, mmd, noise_frame) && + if ((!baking_noise || (baking_noise && resume_noise)) && has_config && manta_needs_realloc(mds->fluid, mmd)) { BKE_fluid_reallocate_fluid(mds, mds->res, 1); } - if (!baking_data && !baking_noise && !mode_replay) { - has_data = manta_update_noise_structures(mds->fluid, mmd, noise_frame); + if (!baking_data && !baking_noise && next_noise) { + has_noise = manta_update_noise_structures(mds->fluid, mmd, noise_frame); } else { has_noise = manta_read_noise(mds->fluid, mmd, noise_frame); @@ -3916,15 +3981,13 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, copy_v3_v3_int(o_min, mds->res_min); copy_v3_v3_int(o_max, mds->res_max); copy_v3_v3_int(o_shift, mds->shift); - if (manta_read_config(mds->fluid, mmd, data_frame) && - manta_needs_realloc(mds->fluid, mmd)) { + if (has_config && manta_needs_realloc(mds->fluid, mmd)) { BKE_fluid_reallocate_copy_fluid( mds, o_res, mds->res, o_min, mds->res_min, o_max, o_shift, mds->shift); } } - if (!baking_data && !baking_noise && !mode_replay) { - /* TODO (sebbas): Confirm if this read call is really needed or not. */ - has_data = manta_update_smoke_structures(mds->fluid, mmd, data_frame); + if (!baking_data && !baking_noise && next_data && next_noise) { + /* Nothing to do here since we already loaded noise grids. */ } else { has_data = manta_read_data(mds->fluid, mmd, data_frame); @@ -3932,14 +3995,15 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, } /* Read data cache only */ else { + has_config = manta_read_config(mds->fluid, mmd, data_frame); + if (with_smoke) { /* Read config and realloc fluid object if needed. */ - if (manta_read_config(mds->fluid, mmd, data_frame) && - manta_needs_realloc(mds->fluid, mmd)) { + if (has_config && manta_needs_realloc(mds->fluid, mmd)) { BKE_fluid_reallocate_fluid(mds, mds->res, 1); } /* Read data cache */ - if (!baking_data && !baking_particles && !baking_mesh && !mode_replay) { + if (!baking_data && !baking_particles && !baking_mesh && next_data) { has_data = manta_update_smoke_structures(mds->fluid, mmd, data_frame); } else { @@ -3947,7 +4011,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, } } if (with_liquid) { - if (!baking_data && !baking_particles && !baking_mesh && !mode_replay) { + if (!baking_data && !baking_particles && !baking_mesh && next_data) { has_data = manta_update_liquid_structures(mds->fluid, mmd, data_frame); } else { @@ -3961,21 +4025,27 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, switch (mode) { case FLUID_DOMAIN_CACHE_FINAL: case FLUID_DOMAIN_CACHE_MODULAR: + if (!baking_data && !baking_noise && !baking_mesh && !baking_particles && !baking_guide) { + bake_cache = false; + } break; case FLUID_DOMAIN_CACHE_REPLAY: default: - baking_data = !has_data; + baking_data = !has_data && (is_startframe || prev_data); if (with_smoke && with_noise) { - baking_noise = !has_noise; + baking_noise = !has_noise && (is_startframe || prev_noise); } if (with_liquid && with_mesh) { - baking_mesh = !has_mesh; + baking_mesh = !has_mesh && (is_startframe || prev_mesh); } if (with_liquid && with_particles) { - baking_particles = !has_particles; + baking_particles = !has_particles && (is_startframe || prev_particles); } - bake_cache = baking_data || baking_noise || baking_mesh || baking_particles; + /* Only bake if time advanced by one frame. */ + if (is_startframe || has_advanced) { + bake_cache = baking_data || baking_noise || baking_mesh || baking_particles; + } break; } @@ -4006,7 +4076,11 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, } if (has_data || baking_data) { if (baking_noise && with_smoke && with_noise) { - manta_bake_noise(mds->fluid, mmd, scene_framenr); + /* Ensure that no bake occurs if domain was minimized by adaptive domain. */ + if (mds->total_cells > 1) { + manta_bake_noise(mds->fluid, mmd, scene_framenr); + } + manta_write_noise(mds->fluid, mmd, scene_framenr); } if (baking_mesh && with_liquid && with_mesh) { manta_bake_mesh(mds->fluid, mmd, scene_framenr); @@ -4016,6 +4090,8 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, } } } + + mds->flags &= ~FLUID_DOMAIN_FILE_LOAD; mmd->time = scene_framenr; } @@ -4097,6 +4173,7 @@ struct Mesh *BKE_fluid_modifier_do( mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_PARTICLES; mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_GUIDE; } + if (!result) { result = BKE_mesh_copy_for_eval(me, false); } @@ -4311,26 +4388,25 @@ static void manta_smoke_calc_transparency(FluidDomainSettings *mds, ViewLayer *v } } -/* get smoke velocity and density at given coordinates - * returns fluid density or -1.0f if outside domain. */ +/* Get fluid velocity and density at given coordinates + * Returns fluid density or -1.0f if outside domain. */ float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3]) { - FluidModifierData *mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid); + FluidModifierData *mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid); zero_v3(velocity); if (mmd && (mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain && mmd->domain->fluid) { FluidDomainSettings *mds = mmd->domain; float time_mult = 25.f * DT_DEFAULT; + float size_mult = MAX3(mds->global_size[0], mds->global_size[1], mds->global_size[2]) / + mds->maxres; float vel_mag; - float *velX = manta_get_velocity_x(mds->fluid); - float *velY = manta_get_velocity_y(mds->fluid); - float *velZ = manta_get_velocity_z(mds->fluid); float density = 0.0f, fuel = 0.0f; float pos[3]; copy_v3_v3(pos, position); manta_pos_to_cell(mds, pos); - /* check if point is outside domain max bounds */ + /* Check if position is outside domain max bounds. */ if (pos[0] < mds->res_min[0] || pos[1] < mds->res_min[1] || pos[2] < mds->res_min[2]) { return -1.0f; } @@ -4343,9 +4419,8 @@ float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velo pos[1] = (pos[1] - mds->res_min[1]) / ((float)mds->res[1]); pos[2] = (pos[2] - mds->res_min[2]) / ((float)mds->res[2]); - /* check if point is outside active area */ - if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS && - mmd->domain->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { + /* Check if position is outside active area. */ + if (mds->type == FLUID_DOMAIN_TYPE_GAS && mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) { return 0.0f; } @@ -4354,21 +4429,22 @@ float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velo } } - /* get interpolated velocity */ - velocity[0] = BLI_voxel_sample_trilinear(velX, mds->res, pos) * mds->global_size[0] * - time_mult; - velocity[1] = BLI_voxel_sample_trilinear(velY, mds->res, pos) * mds->global_size[1] * - time_mult; - velocity[2] = BLI_voxel_sample_trilinear(velZ, mds->res, pos) * mds->global_size[2] * - time_mult; + /* Get interpolated velocity at given position. */ + velocity[0] = BLI_voxel_sample_trilinear(manta_get_velocity_x(mds->fluid), mds->res, pos); + velocity[1] = BLI_voxel_sample_trilinear(manta_get_velocity_y(mds->fluid), mds->res, pos); + velocity[2] = BLI_voxel_sample_trilinear(manta_get_velocity_z(mds->fluid), mds->res, pos); - /* convert velocity direction to global space */ + /* Convert simulation units to Blender units. */ + mul_v3_fl(velocity, size_mult); + mul_v3_fl(velocity, time_mult); + + /* Convert velocity direction to global space. */ vel_mag = len_v3(velocity); mul_mat3_m4_v3(mds->obmat, velocity); normalize_v3(velocity); mul_v3_fl(velocity, vel_mag); - /* use max value of fuel or smoke density */ + /* Use max value of fuel or smoke density. */ density = BLI_voxel_sample_trilinear(manta_smoke_get_density(mds->fluid), mds->res, pos); if (manta_smoke_has_fuel(mds->fluid)) { fuel = BLI_voxel_sample_trilinear(manta_smoke_get_fuel(mds->fluid), mds->res, pos); @@ -4422,11 +4498,11 @@ void BKE_fluid_particle_system_create(struct Main *bmain, BLI_addtail(&ob->particlesystem, psys); /* add modifier */ - pmmd = (ParticleSystemModifierData *)modifier_new(eModifierType_ParticleSystem); + pmmd = (ParticleSystemModifierData *)BKE_modifier_new(eModifierType_ParticleSystem); BLI_strncpy(pmmd->modifier.name, psys_name, sizeof(pmmd->modifier.name)); pmmd->psys = psys; BLI_addtail(&ob->modifiers, pmmd); - modifier_unique_name(&ob->modifiers, (ModifierData *)pmmd); + BKE_modifier_unique_name(&ob->modifiers, (ModifierData *)pmmd); } void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_type) @@ -4440,7 +4516,7 @@ void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_typ /* clear modifier */ pmmd = psys_get_modifier(ob, psys); BLI_remlink(&ob->modifiers, pmmd); - modifier_free((ModifierData *)pmmd); + BKE_modifier_free((ModifierData *)pmmd); /* clear particle system */ BLI_remlink(&ob->particlesystem, psys); @@ -4459,6 +4535,18 @@ void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_typ * Use for versioning, even when fluids are disabled. * \{ */ +void BKE_fluid_cache_startframe_set(FluidDomainSettings *settings, int value) +{ + settings->cache_frame_start = (value > settings->cache_frame_end) ? settings->cache_frame_end : + value; +} + +void BKE_fluid_cache_endframe_set(FluidDomainSettings *settings, int value) +{ + settings->cache_frame_end = (value < settings->cache_frame_start) ? settings->cache_frame_start : + value; +} + void BKE_fluid_cachetype_mesh_set(FluidDomainSettings *settings, int cache_mesh_format) { if (cache_mesh_format == settings->cache_mesh_format) { @@ -4633,6 +4721,7 @@ static void BKE_fluid_modifier_freeFlow(FluidModifierData *mmd) } mmd->flow->verts_old = NULL; mmd->flow->numverts = 0; + mmd->flow->flags &= ~FLUID_FLOW_NEEDS_UPDATE; MEM_freeN(mmd->flow); mmd->flow = NULL; @@ -4652,6 +4741,7 @@ static void BKE_fluid_modifier_freeEffector(FluidModifierData *mmd) } mmd->effector->verts_old = NULL; mmd->effector->numverts = 0; + mmd->effector->flags &= ~FLUID_EFFECTOR_NEEDS_UPDATE; MEM_freeN(mmd->effector); mmd->effector = NULL; @@ -4690,6 +4780,7 @@ static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *mmd, bool need } mmd->flow->verts_old = NULL; mmd->flow->numverts = 0; + mmd->flow->flags &= ~FLUID_FLOW_NEEDS_UPDATE; } else if (mmd->effector) { if (mmd->effector->verts_old) { @@ -4697,6 +4788,7 @@ static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *mmd, bool need } mmd->effector->verts_old = NULL; mmd->effector->numverts = 0; + mmd->effector->flags &= ~FLUID_EFFECTOR_NEEDS_UPDATE; } } @@ -4743,13 +4835,13 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd) mmd->domain->adapt_threshold = 0.02f; /* fluid domain options */ - mmd->domain->maxres = 64; + mmd->domain->maxres = 32; mmd->domain->solver_res = 3; mmd->domain->border_collisions = 0; // open domain mmd->domain->flags = FLUID_DOMAIN_USE_DISSOLVE_LOG | FLUID_DOMAIN_USE_ADAPTIVE_TIME; mmd->domain->gravity[0] = 0.0f; mmd->domain->gravity[1] = 0.0f; - mmd->domain->gravity[2] = -1.0f; + mmd->domain->gravity[2] = -9.81f; mmd->domain->active_fields = 0; mmd->domain->type = FLUID_DOMAIN_TYPE_GAS; mmd->domain->boundary_width = 1; @@ -4796,7 +4888,6 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd) mmd->domain->surface_tension = 0.0f; mmd->domain->viscosity_base = 1.0f; mmd->domain->viscosity_exponent = 6.0f; - mmd->domain->domain_size = 0.5f; /* mesh options */ mmd->domain->mesh_velocities = NULL; @@ -4838,14 +4929,14 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd) /* cache options */ mmd->domain->cache_frame_start = 1; - mmd->domain->cache_frame_end = 50; + mmd->domain->cache_frame_end = 250; mmd->domain->cache_frame_pause_data = 0; mmd->domain->cache_frame_pause_noise = 0; mmd->domain->cache_frame_pause_mesh = 0; mmd->domain->cache_frame_pause_particles = 0; mmd->domain->cache_frame_pause_guide = 0; mmd->domain->cache_flag = 0; - mmd->domain->cache_type = FLUID_DOMAIN_CACHE_MODULAR; + mmd->domain->cache_type = FLUID_DOMAIN_CACHE_REPLAY; mmd->domain->cache_mesh_format = FLUID_DOMAIN_FILE_BIN_OBJECT; #ifdef WITH_OPENVDB mmd->domain->cache_data_format = FLUID_DOMAIN_FILE_OPENVDB; @@ -4858,7 +4949,7 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd) #endif char cache_name[64]; BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name); - modifier_path_init( + BKE_modifier_path_init( mmd->domain->cache_directory, sizeof(mmd->domain->cache_directory), cache_name); /* time options */ @@ -5040,7 +5131,6 @@ void BKE_fluid_modifier_copy(const struct FluidModifierData *mmd, tmds->surface_tension = mds->surface_tension; tmds->viscosity_base = mds->viscosity_base; tmds->viscosity_exponent = mds->viscosity_exponent; - tmds->domain_size = mds->domain_size; /* mesh options */ if (mds->mesh_velocities) { |