Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastián Barschkis <sebbas@sebbas.org>2020-03-22 23:46:30 +0300
committerSebastián Barschkis <sebbas@sebbas.org>2020-03-22 23:46:43 +0300
commit0c571db4add35ae78089cd8e88fa6f7a9125b123 (patch)
treed5342a8d040d0429685426d8858db729f1d5d600
parent95b6090afca21b2e03bcd278ae94d1321e407029 (diff)
Fix T73988: Mantaflow fluid simulation - Particles for Spray, Foam and Bubbles are one frame ahead of Mesh
Fixes an issue with secondary particles being out of sync with the main simulation. Cleaned up the secondary particle code in general too (making sure that all solver attributes - timestep, framelength, etc. - are set correctly).
-rw-r--r--intern/mantaflow/intern/MANTA_main.cpp2
-rw-r--r--intern/mantaflow/intern/strings/fluid_script.h44
-rw-r--r--intern/mantaflow/intern/strings/liquid_script.h58
-rw-r--r--source/blender/blenkernel/intern/fluid.c41
4 files changed, 85 insertions, 60 deletions
diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp
index 5d35de7898f..c169d242583 100644
--- a/intern/mantaflow/intern/MANTA_main.cpp
+++ b/intern/mantaflow/intern/MANTA_main.cpp
@@ -837,6 +837,8 @@ std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *m
ss << mmd->domain->flame_smoke_color[2];
else if (varName == "CURRENT_FRAME")
ss << mmd->time;
+ else if (varName == "START_FRAME")
+ ss << mmd->domain->cache_frame_start;
else if (varName == "END_FRAME")
ss << mmd->domain->cache_frame_end;
else if (varName == "CACHE_DATA_FORMAT")
diff --git a/intern/mantaflow/intern/strings/fluid_script.h b/intern/mantaflow/intern/strings/fluid_script.h
index c442dd56c09..0aad0546aea 100644
--- a/intern/mantaflow/intern/strings/fluid_script.h
+++ b/intern/mantaflow/intern/strings/fluid_script.h
@@ -123,6 +123,11 @@ cflCond_s$ID$ = $CFL$\n\
timestepsMin_s$ID$ = $TIMESTEPS_MIN$\n\
timestepsMax_s$ID$ = $TIMESTEPS_MAX$\n\
\n\
+# Start and stop for simulation\n\
+current_frame_s$ID$ = $CURRENT_FRAME$\n\
+start_frame_s$ID$ = $START_FRAME$\n\
+end_frame_s$ID$ = $END_FRAME$\n\
+\n\
# Fluid diffusion / viscosity\n\
domainSize_s$ID$ = $FLUID_DOMAIN_SIZE$ # longest domain side in meters\n\
viscosity_s$ID$ = $FLUID_VISCOSITY$ / (domainSize_s$ID$*domainSize_s$ID$) # kinematic viscosity in m^2/s\n\
@@ -208,6 +213,8 @@ def fluid_adapt_time_step_$ID$():\n\
# time params are animatable\n\
s$ID$.frameLength = frameLength_s$ID$\n\
s$ID$.cfl = cflCond_s$ID$\n\
+ s$ID$.timestepMin = s$ID$.frameLength / max(1, timestepsMax_s$ID$)\n\
+ s$ID$.timestepMax = s$ID$.frameLength / max(1, timestepsMin_s$ID$)\n\
\n\
# ensure that vel grid is full (remember: adaptive domain can reallocate solver)\n\
copyRealToVec3(sourceX=x_vel_s$ID$, sourceY=y_vel_s$ID$, sourceZ=z_vel_s$ID$, target=vel_s$ID$)\n\
@@ -225,7 +232,7 @@ const std::string fluid_alloc =
mantaMsg('Fluid alloc data')\n\
flags_s$ID$ = s$ID$.create(FlagGrid)\n\
vel_s$ID$ = s$ID$.create(MACGrid)\n\
-velC_s$ID$ = s$ID$.create(MACGrid)\n\
+velTmp_s$ID$ = s$ID$.create(MACGrid)\n\
x_vel_s$ID$ = s$ID$.create(RealGrid)\n\
y_vel_s$ID$ = s$ID$.create(RealGrid)\n\
z_vel_s$ID$ = s$ID$.create(RealGrid)\n\
@@ -247,7 +254,7 @@ phiIn_s$ID$.setConst(9999)\n\
phiOut_s$ID$.setConst(9999)\n\
\n\
# Keep track of important objects in dict to load them later on\n\
-fluid_data_dict_final_s$ID$ = dict(vel=vel_s$ID$)\n\
+fluid_data_dict_final_s$ID$ = dict(vel=vel_s$ID$, velTmp=velTmp_s$ID$)\n\
fluid_data_dict_resume_s$ID$ = dict(phiObs=phiObs_s$ID$, phiIn=phiIn_s$ID$, phiOut=phiOut_s$ID$, flags=flags_s$ID$)\n";
const std::string fluid_alloc_obstacle =
@@ -493,7 +500,8 @@ def bake_fluid_process_data_$ID$(framenr, format_data, format_particles, format_
mantaMsg('Bake fluid data')\n\
\n\
s$ID$.frame = framenr\n\
- # Must not set 'timeTotal' here. Remember, this function is called from manta.c while-loop\n\
+ s$ID$.frameLength = frameLength_s$ID$\n\
+ s$ID$.timeTotal = timeTotal_s$ID$\n\
\n\
start_time = time.time()\n\
if using_smoke_s$ID$:\n\
@@ -514,9 +522,9 @@ def bake_noise_process_$ID$(framenr, format_data, format_noise, path_data, path_
mantaMsg('Bake fluid noise')\n\
\n\
sn$ID$.frame = framenr\n\
- sn$ID$.timeTotal = (framenr-1) * frameLength_s$ID$\n\
- sn$ID$.timestep = dt0_s$ID$\n\
- mantaMsg('sn$ID$.timeTotal: ' + str(sn$ID$.timeTotal))\n\
+ sn$ID$.frameLength = frameLength_s$ID$\n\
+ sn$ID$.timeTotal = abs(framenr - start_frame_s$ID$) * frameLength_s$ID$\n\
+ sn$ID$.timestep = frameLength_s$ID$ # no adaptive timestep for noise\n\
\n\
smoke_step_noise_$ID$(framenr)\n\
smoke_save_noise_$ID$(path_noise, framenr, format_noise, resumable)\n\
@@ -533,8 +541,9 @@ def bake_mesh_process_$ID$(framenr, format_data, format_mesh, format_particles,
mantaMsg('Bake fluid mesh')\n\
\n\
sm$ID$.frame = framenr\n\
- sm$ID$.timeTotal = (framenr-1) * frameLength_s$ID$\n\
- sm$ID$.timestep = dt0_s$ID$\n\
+ sm$ID$.frameLength = frameLength_s$ID$\n\
+ sm$ID$.timeTotal = abs(framenr - start_frame_s$ID$) * frameLength_s$ID$\n\
+ sm$ID$.timestep = frameLength_s$ID$ # no adaptive timestep for mesh\n\
\n\
#if using_smoke_s$ID$:\n\
# TODO (sebbas): Future update could include smoke mesh (vortex sheets)\n\
@@ -556,8 +565,9 @@ def bake_particles_process_$ID$(framenr, format_data, format_particles, path_dat
mantaMsg('Bake secondary particles')\n\
\n\
sp$ID$.frame = framenr\n\
- sp$ID$.timeTotal = (framenr-1) * frameLength_s$ID$\n\
- sp$ID$.timestep = dt0_s$ID$\n\
+ sp$ID$.frameLength = frameLength_s$ID$\n\
+ sp$ID$.timeTotal = abs(framenr - start_frame_s$ID$) * frameLength_s$ID$\n\
+ sp$ID$.timestep = frameLength_s$ID$ # no adaptive timestep for particles\n\
\n\
#if using_smoke_s$ID$:\n\
# TODO (sebbas): Future update could include smoke particles (e.g. fire sparks)\n\
@@ -710,28 +720,24 @@ file_format_noise = '$CACHE_NOISE_FORMAT$'\n\
file_format_particles = '$CACHE_PARTICLE_FORMAT$'\n\
file_format_mesh = '$CACHE_MESH_FORMAT$'\n\
\n\
-# Start and stop for simulation\n\
-current_frame = $CURRENT_FRAME$\n\
-end_frame = $END_FRAME$\n\
-\n\
# How many frame to load from cache\n\
from_cache_cnt = 100\n\
\n\
loop_cnt = 0\n\
-while current_frame <= end_frame:\n\
+while current_frame_s$ID$ <= end_frame_s$ID$:\n\
\n\
# Load already simulated data from cache:\n\
if loop_cnt < from_cache_cnt:\n\
- load(current_frame, cache_resumable)\n\
+ load(current_frame_s$ID$, cache_resumable)\n\
\n\
# Otherwise simulate new data\n\
else:\n\
- while(s$ID$.frame <= current_frame):\n\
+ while(s$ID$.frame <= current_frame_s$ID$):\n\
if using_adaptTime_s$ID$:\n\
fluid_adapt_time_step_$ID$()\n\
- step(current_frame)\n\
+ step(current_frame_s$ID$)\n\
\n\
- current_frame += 1\n\
+ current_frame_s$ID$ += 1\n\
loop_cnt += 1\n\
\n\
if gui:\n\
diff --git a/intern/mantaflow/intern/strings/liquid_script.h b/intern/mantaflow/intern/strings/liquid_script.h
index 23ec16b9d84..2376d49aace 100644
--- a/intern/mantaflow/intern/strings/liquid_script.h
+++ b/intern/mantaflow/intern/strings/liquid_script.h
@@ -133,9 +133,8 @@ pLifeSnd_pp$ID$ = ppSnd_sp$ID$.create(PdataReal)\n\
vel_sp$ID$ = sp$ID$.create(MACGrid)\n\
flags_sp$ID$ = sp$ID$.create(FlagGrid)\n\
phi_sp$ID$ = sp$ID$.create(LevelsetGrid)\n\
-phiIn_sp$ID$ = sp$ID$.create(LevelsetGrid)\n\
phiObs_sp$ID$ = sp$ID$.create(LevelsetGrid)\n\
-phiObsIn_sp$ID$ = sp$ID$.create(LevelsetGrid)\n\
+phiOut_sp$ID$ = sp$ID$.create(LevelsetGrid)\n\
normal_sp$ID$ = sp$ID$.create(VecGrid)\n\
neighborRatio_sp$ID$ = sp$ID$.create(RealGrid)\n\
trappedAir_sp$ID$ = sp$ID$.create(RealGrid)\n\
@@ -144,9 +143,8 @@ kineticEnergy_sp$ID$ = sp$ID$.create(RealGrid)\n\
\n\
# Set some initial values\n\
phi_sp$ID$.setConst(9999)\n\
-phiIn_sp$ID$.setConst(9999)\n\
phiObs_sp$ID$.setConst(9999)\n\
-phiObsIn_sp$ID$.setConst(9999)\n\
+phiOut_sp$ID$.setConst(9999)\n\
\n\
# Keep track of important objects in dict to load them later on\n\
liquid_particles_dict_final_s$ID$ = dict(ppSnd=ppSnd_sp$ID$, pVelSnd=pVelSnd_pp$ID$, pLifeSnd=pLifeSnd_pp$ID$)\n\
@@ -229,13 +227,15 @@ def liquid_step_$ID$():\n\
mantaMsg('Pushing particles out of obstacles')\n\
pushOutofObs(parts=pp_s$ID$, flags=flags_s$ID$, phiObs=phiObs_s$ID$)\n\
\n\
+ # save original states for later (used during mesh / secondary particle creation)\n\
+ phiTmp_s$ID$.copyFrom(phi_s$ID$)\n\
+ velTmp_s$ID$.copyFrom(vel_s$ID$)\n\
+ \n\
mantaMsg('Advecting phi')\n\
advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=phi_s$ID$, order=1) # first order is usually enough\n\
mantaMsg('Advecting velocity')\n\
advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=vel_s$ID$, order=2)\n\
\n\
- phiTmp_s$ID$.copyFrom(phi_s$ID$) # save original phi for later use in mesh creation\n\
- \n\
# create level set of particles\n\
gridParticleIndex(parts=pp_s$ID$, flags=flags_s$ID$, indexSys=pindex_s$ID$, index=gpi_s$ID$)\n\
unionParticleLevelset(parts=pp_s$ID$, indexSys=pindex_s$ID$, flags=flags_s$ID$, index=gpi_s$ID$, phi=phiParts_s$ID$, radiusFactor=radiusFactor_s$ID$)\n\
@@ -308,7 +308,13 @@ const std::string liquid_step_mesh =
def liquid_step_mesh_$ID$():\n\
mantaMsg('Liquid step mesh')\n\
\n\
- interpolateGrid(target=phi_sm$ID$, source=phiTmp_s$ID$)\n\
+ # no upres: just use the loaded grids\n\
+ if upres_sm$ID$ <= 1:\n\
+ phi_sm$ID$.copyFrom(phiTmp_s$ID$)\n\
+ \n\
+ # with upres: recreate grids\n\
+ else:\n\
+ interpolateGrid(target=phi_sm$ID$, source=phiTmp_s$ID$)\n\
\n\
# create surface\n\
pp_sm$ID$.readParticles(pp_s$ID$)\n\
@@ -342,30 +348,36 @@ def liquid_step_particles_$ID$():\n\
\n\
# no upres: just use the loaded grids\n\
if upres_sp$ID$ <= 1:\n\
- flags_sp$ID$.copyFrom(flags_s$ID$)\n\
- vel_sp$ID$.copyFrom(vel_s$ID$)\n\
+ vel_sp$ID$.copyFrom(velTmp_s$ID$)\n\
phiObs_sp$ID$.copyFrom(phiObs_s$ID$)\n\
- phi_sp$ID$.copyFrom(phi_s$ID$)\n\
+ phi_sp$ID$.copyFrom(phiTmp_s$ID$)\n\
+ phiOut_sp$ID$.copyFrom(phiOut_s$ID$)\n\
\n\
# with upres: recreate grids\n\
else:\n\
# create highres grids by interpolation\n\
- interpolateMACGrid(target=vel_sp$ID$, source=vel_s$ID$)\n\
- interpolateGrid(target=phi_sp$ID$, source=phi_s$ID$)\n\
- flags_sp$ID$.initDomain(boundaryWidth=boundaryWidth_s$ID$, phiWalls=phiObs_sp$ID$, outflow=boundConditions_s$ID$)\n\
- flags_sp$ID$.updateFromLevelset(levelset=phi_sp$ID$)\n\
+ interpolateMACGrid(target=vel_sp$ID$, source=velTmp_s$ID$)\n\
+ interpolateGrid(target=phiObs_sp$ID$, source=phiObs_s$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\
- # actual secondary simulation\n\
- #extrapolateLsSimple(phi=phi_sp$ID$, distance=radius+1, inside=True)\n\
+ # Actual secondary particle simulation\n\
flipComputeSecondaryParticlePotentials(potTA=trappedAir_sp$ID$, potWC=waveCrest_sp$ID$, potKE=kineticEnergy_sp$ID$, neighborRatio=neighborRatio_sp$ID$, flags=flags_sp$ID$, v=vel_sp$ID$, normal=normal_sp$ID$, phi=phi_sp$ID$, radius=pot_radius_sp$ID$, tauMinTA=tauMin_ta_sp$ID$, tauMaxTA=tauMax_ta_sp$ID$, tauMinWC=tauMin_wc_sp$ID$, tauMaxWC=tauMax_wc_sp$ID$, tauMinKE=tauMin_k_sp$ID$, tauMaxKE=tauMax_k_sp$ID$, scaleFromManta=scaleFromManta_sp$ID$)\n\
- flipSampleSecondaryParticles(mode='single', flags=flags_sp$ID$, v=vel_sp$ID$, pts_sec=ppSnd_sp$ID$, v_sec=pVelSnd_pp$ID$, l_sec=pLifeSnd_pp$ID$, lMin=lMin_sp$ID$, lMax=lMax_sp$ID$, potTA=trappedAir_sp$ID$, potWC=waveCrest_sp$ID$, potKE=kineticEnergy_sp$ID$, neighborRatio=neighborRatio_sp$ID$, c_s=c_s_sp$ID$, c_b=c_b_sp$ID$, k_ta=k_ta_sp$ID$, k_wc=k_wc_sp$ID$, dt=s$ID$.frameLength)\n\
- flipUpdateSecondaryParticles(mode='linear', pts_sec=ppSnd_sp$ID$, v_sec=pVelSnd_pp$ID$, l_sec=pLifeSnd_pp$ID$, f_sec=pForceSnd_pp$ID$, flags=flags_sp$ID$, v=vel_sp$ID$, neighborRatio=neighborRatio_sp$ID$, radius=update_radius_sp$ID$, gravity=gravity_s$ID$, k_b=k_b_sp$ID$, k_d=k_d_sp$ID$, c_s=c_s_sp$ID$, c_b=c_b_sp$ID$, dt=s$ID$.frameLength)\n\
+ flipSampleSecondaryParticles(mode='single', flags=flags_sp$ID$, v=vel_sp$ID$, pts_sec=ppSnd_sp$ID$, v_sec=pVelSnd_pp$ID$, l_sec=pLifeSnd_pp$ID$, lMin=lMin_sp$ID$, lMax=lMax_sp$ID$, potTA=trappedAir_sp$ID$, potWC=waveCrest_sp$ID$, potKE=kineticEnergy_sp$ID$, neighborRatio=neighborRatio_sp$ID$, c_s=c_s_sp$ID$, c_b=c_b_sp$ID$, k_ta=k_ta_sp$ID$, k_wc=k_wc_sp$ID$, dt=sp$ID$.timestep)\n\
+ flipUpdateSecondaryParticles(mode='linear', pts_sec=ppSnd_sp$ID$, v_sec=pVelSnd_pp$ID$, l_sec=pLifeSnd_pp$ID$, f_sec=pForceSnd_pp$ID$, flags=flags_sp$ID$, v=vel_sp$ID$, neighborRatio=neighborRatio_sp$ID$, radius=update_radius_sp$ID$, gravity=gravity_s$ID$, k_b=k_b_sp$ID$, k_d=k_d_sp$ID$, c_s=c_s_sp$ID$, c_b=c_b_sp$ID$, dt=sp$ID$.timestep)\n\
if $SNDPARTICLE_BOUNDARY_PUSHOUT$:\n\
- pushOutofObs(parts = ppSnd_sp$ID$, flags = flags_sp$ID$, phiObs = phiObs_sp$ID$, shift = 1.0)\n\
- flipDeleteParticlesInObstacle(pts=ppSnd_sp$ID$, flags=flags_sp$ID$)\n\
- #debugGridInfo(flags = flags_sp$ID$, grid = trappedAir_sp$ID$, name = 'Trapped Air')\n\
- #debugGridInfo(flags = flags_sp$ID$, grid = waveCrest_sp$ID$, name = 'Wave Crest')\n\
- #debugGridInfo(flags = flags_sp$ID$, grid = kineticEnergy_sp$ID$, name = 'Kinetic Energy')\n";
+ pushOutofObs(parts=ppSnd_sp$ID$, flags=flags_sp$ID$, phiObs=phiObs_sp$ID$, shift=1.0)\n\
+ flipDeleteParticlesInObstacle(pts=ppSnd_sp$ID$, flags=flags_sp$ID$) # delete particles inside obstacle and outflow cells\n\
+ \n\
+ # Print debug information in the console\n\
+ if 0:\n\
+ debugGridInfo(flags=flags_sp$ID$, grid=trappedAir_sp$ID$, name='Trapped Air')\n\
+ debugGridInfo(flags=flags_sp$ID$, grid=waveCrest_sp$ID$, name='Wave Crest')\n\
+ debugGridInfo(flags=flags_sp$ID$, grid=kineticEnergy_sp$ID$, name='Kinetic Energy')\n";
//////////////////////////////////////////////////////////////////////
// IMPORT
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 15f3fdf6a40..58a1ae28d42 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -538,7 +538,7 @@ 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 = (scene_framenr - 1) * mds->frame_length;
+ mds->time_total = abs(scene_framenr - mds->cache_frame_start) * mds->frame_length;
mmd->time = scene_framenr;
@@ -3561,7 +3561,7 @@ static int manta_step(
BLI_mutex_lock(&object_update_lock);
/* Loop as long as time_per_frame (sum of sub dt's) does not exceed actual framelength. */
- while (time_per_frame < frame_length) {
+ while (time_per_frame + FLT_EPSILON < frame_length) {
manta_adapt_timestep(mds->fluid);
dt = manta_get_timestep(mds->fluid);
@@ -3569,10 +3569,6 @@ static int manta_step(
* new MANTA object). */
mds->dt = dt;
- /* Count for how long this while loop is running. */
- time_per_frame += dt;
- time_total += dt;
-
/* Calculate inflow geometry. */
update_flowsfluids(depsgraph, scene, ob, mds, time_per_frame, frame_length, frame, dt);
@@ -3596,11 +3592,15 @@ static int manta_step(
if (mds->total_cells > 1) {
update_effectors(depsgraph, scene, ob, mds, dt);
manta_bake_data(mds->fluid, mmd, frame);
-
- mds->time_per_frame = time_per_frame;
- mds->time_total = time_total;
}
+ /* Count for how long this while loop is running. */
+ time_per_frame += dt;
+ time_total += dt;
+
+ 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;
@@ -3701,8 +3701,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
bool is_startframe;
is_startframe = (scene_framenr == mds->cache_frame_start);
- /* Reset fluid if no fluid present (obviously)
- * or if timeline gets reset to startframe */
+ /* Reset fluid if no fluid present. */
if (!mds->fluid) {
BKE_fluid_modifier_reset_ex(mmd, false);
@@ -3713,7 +3712,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
}
BLI_assert(mds->fluid);
- /* Guiding parent res pointer needs initialization */
+ /* Guiding parent res pointer needs initialization. */
guide_parent = mds->guide_parent;
if (guide_parent) {
mmd_parent = (FluidModifierData *)modifiers_findByType(guide_parent, eModifierType_Fluid);
@@ -3722,12 +3721,13 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
}
}
- /* ensure that time parameters are initialized correctly before every step */
+ /* Ensure that time parameters are initialized correctly before every step. */
float fps = scene->r.frs_sec / scene->r.frs_sec_base;
mds->frame_length = DT_DEFAULT * (25.0f / fps) * mds->time_scale;
mds->dt = mds->frame_length;
mds->time_per_frame = 0;
- mds->time_total = (scene_framenr - 1) * mds->frame_length;
+ /* 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);
@@ -3743,7 +3743,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
MEM_freeN(objs);
}
- /* Ensure cache directory is not relative */
+ /* Ensure cache directory is not relative. */
const char *relbase = modifier_path_relbase_from_global(ob);
BLI_path_abs(mds->cache_directory, relbase);
@@ -3801,7 +3801,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
/* Ensure positivity of previous frame. */
CLAMP(prev_frame, 1, prev_frame);
- /* Cache mode specific settings */
+ /* Cache mode specific settings. */
switch (mode) {
case FLUID_DOMAIN_CACHE_FINAL:
/* Just load the data that has already been baked */
@@ -3872,8 +3872,13 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
/* Read particles cache. */
if (with_liquid && with_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);
+ if (!baking_data && !baking_particles && !mode_replay) {
+ /* Update particle data from file is faster than via Python (manta_read_particles()). */
+ has_particles = manta_update_particle_structures(mds->fluid, mmd, particles_frame);
+ }
+ else {
+ has_particles = manta_read_particles(mds->fluid, mmd, particles_frame);
+ }
}
/* Read guide cache. */