Files
blender-portable-repo/extensions/user_default/flip_fluids_addon/bake.py
T
2026-03-17 15:25:32 -06:00

3317 lines
158 KiB
Python

# Blender FLIP Fluids Add-on
# Copyright (C) 2025 Ryan L. Guy & Dennis Fassbaender
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys, os, shutil, json, traceback, math, time
from .objects import flip_fluid_map
from .objects import flip_fluid_geometry_database
from .operators import bake_operators
from .filesystem import filesystem_protection_layer as fpl
from .utils import version_compatibility_utils as vcu
from . import bl_info
from .ffengine import (
ffengine,
mixbox,
FluidSimulation,
TriangleMesh,
Vector3,
AABB,
MeshObject,
MeshFluidSource,
ForceFieldPoint,
ForceFieldSurface,
ForceFieldVolume,
ForceFieldCurve,
)
from .utils import cache_utils
FLUIDSIM_OBJECT = None
SIMULATION_DATA = None
CACHE_DIRECTORY = ""
GEOMETRY_DATABASE = None
class LibraryVersionError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return str(self.value)
def __set_simulation_object(fluidsim_object):
global FLUIDSIM_OBJECT
FLUIDSIM_OBJECT = fluidsim_object
def __get_simulation_object():
global FLUIDSIM_OBJECT
return FLUIDSIM_OBJECT
def __set_simulation_data(data):
global SIMULATION_DATA
SIMULATION_DATA = data
def __get_simulation_data():
global SIMULATION_DATA
return SIMULATION_DATA
def __set_cache_directory(cache_directory):
global CACHE_DIRECTORY
CACHE_DIRECTORY = cache_directory
def __get_cache_directory():
global CACHE_DIRECTORY
return CACHE_DIRECTORY
def __set_geometry_database(geometry_database):
global GEOMETRY_DATABASE
GEOMETRY_DATABASE = geometry_database
def __get_geometry_database():
global GEOMETRY_DATABASE
return GEOMETRY_DATABASE
def __get_export_directory():
return os.path.join(CACHE_DIRECTORY, "export")
def __get_geometry_database_filepath():
data = __get_simulation_data()
return data.domain_data.initialize.geometry_database_filepath
def __get_name_slug(object_name):
return cache_utils.string_to_cache_slug(object_name)
def __is_object_dynamic(object_name):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
return geometry_database.is_object_dynamic(name_slug)
def __get_timeline_frame():
fluidsim = __get_simulation_object()
data = __get_simulation_data()
frame_start = data.domain_data.initialize.frame_start
return fluidsim.get_current_frame() + frame_start
def __get_frame_id():
fluidsim = __get_simulation_object()
return fluidsim.get_current_frame()
def __extract_static_mesh(object_name):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
bobj_data = geometry_database.get_mesh_static(name_slug)
if bobj_data is None:
msg = "Error extracting mesh data. Exported object not found: <" + object_name + ">"
raise Exception(msg)
data = __get_simulation_data()
scale = data.domain_data.initialize.scale
bbox = data.domain_data.initialize.bbox
tmesh = TriangleMesh.from_bobj(bobj_data)
tmesh.translate(-bbox.x, -bbox.y, -bbox.z)
tmesh.scale(scale)
return tmesh
def __extract_transform_data(object_name, frameno):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
matrix_coefficients = geometry_database.get_mesh_keyframed_transform(name_slug, frameno)
if matrix_coefficients is None:
msg = "Error extracting mesh transforms. Exported object not found: <" + object_name + ">"
raise Exception(msg)
return matrix_coefficients
def __extract_keyframed_mesh(object_name, frameno):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
bobj_data = geometry_database.get_mesh_static(name_slug)
if bobj_data is None:
msg = "Error extracting mesh data. Exported object not found: <" + object_name + ">"
raise Exception(msg)
tmesh = TriangleMesh.from_bobj(bobj_data)
transform_data = __extract_transform_data(object_name, frameno)
tmesh.apply_transform(transform_data)
data = __get_simulation_data()
scale = data.domain_data.initialize.scale
bbox = data.domain_data.initialize.bbox
tmesh.translate(-bbox.x, -bbox.y, -bbox.z)
tmesh.scale(scale)
return tmesh
def __extract_animated_mesh(object_name, frameno):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
bobj_data = geometry_database.get_mesh_animated(name_slug, frameno)
data = __get_simulation_data()
scale = data.domain_data.initialize.scale
bbox = data.domain_data.initialize.bbox
tmesh = TriangleMesh.from_bobj(bobj_data)
tmesh.translate(-bbox.x, -bbox.y, -bbox.z)
tmesh.scale(scale)
return tmesh
def __extract_mesh(object_name, frameno):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
motion_type = geometry_database.get_object_motion_export_type(name_slug)
if motion_type == 'STATIC':
return __extract_static_mesh(object_name)
elif motion_type == 'KEYFRAMED':
return __extract_keyframed_mesh(object_name, frameno)
elif motion_type == 'ANIMATED':
return __extract_animated_mesh(object_name, frameno)
def __extract_static_frame_mesh(object_name):
return __extract_static_mesh(object_name)
def __extract_force_field_mesh(object_name, frame_id=0):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
export_dict = geometry_database.get_object_geometry_export_types(name_slug)
if export_dict['mesh']:
return __extract_mesh(object_name, frame_id)
elif export_dict['centroid']:
centroid = __extract_centroid(object_name, frame_id)
tmesh = TriangleMesh()
tmesh.vertices.extend([centroid[0], centroid[1], centroid[2]])
return tmesh
elif export_dict['curve']:
return __extract_curve_mesh(object_name, frame_id)
def __extract_keyframed_frame_meshes(object_name, frameno):
mesh_current = __extract_keyframed_mesh(object_name, frameno)
if frameno - 1 < 0 or not __keyframed_mesh_exists(object_name, frameno - 1):
mesh_previous = mesh_current
else:
mesh_previous = __extract_keyframed_mesh(object_name, frameno - 1)
if not __keyframed_mesh_exists(object_name, frameno + 1):
mesh_next = mesh_current
else:
mesh_next = __extract_keyframed_mesh(object_name, frameno + 1)
return mesh_previous, mesh_current, mesh_next
def __extract_animated_frame_meshes(object_name, frameno):
mesh_current = __extract_animated_mesh(object_name, frameno)
if frameno - 1 < 0 or not __animated_mesh_exists(object_name, frameno - 1):
mesh_previous = mesh_current
else:
mesh_previous = __extract_animated_mesh(object_name, frameno - 1)
if not __animated_mesh_exists(object_name, frameno + 1):
mesh_next = mesh_current
else:
mesh_next = __extract_animated_mesh(object_name, frameno + 1)
return mesh_previous, mesh_current, mesh_next
def __extract_keyframed_frame_centroid_meshes(object_name, frameno):
mesh_current = __extract_force_field_mesh(object_name, frameno)
if frameno - 1 < 0 or not __keyframed_centroid_exists(object_name, frameno - 1):
mesh_previous = mesh_current
else:
mesh_previous = __extract_force_field_mesh(object_name, frameno - 1)
if not __keyframed_centroid_exists(object_name, frameno + 1):
mesh_next = mesh_current
else:
mesh_next = __extract_force_field_mesh(object_name, frameno + 1)
return mesh_previous, mesh_current, mesh_next
def __extract_animated_frame_centroid_meshes(object_name, frameno):
mesh_current = __extract_force_field_mesh(object_name, frameno)
if frameno - 1 < 0 or not __animated_centroid_exists(object_name, frameno - 1):
mesh_previous = mesh_current
else:
mesh_previous = __extract_force_field_mesh(object_name, frameno - 1)
if not __animated_centroid_exists(object_name, frameno + 1):
mesh_next = mesh_current
else:
mesh_next = __extract_force_field_mesh(object_name, frameno + 1)
return mesh_previous, mesh_current, mesh_next
def __extract_keyframed_frame_curve_meshes(object_name, frameno):
mesh_current = __extract_force_field_mesh(object_name, frameno)
if frameno - 1 < 0 or not __keyframed_curve_exists(object_name, frameno - 1):
mesh_previous = mesh_current
else:
mesh_previous = __extract_force_field_mesh(object_name, frameno - 1)
if not __keyframed_curve_exists(object_name, frameno + 1):
mesh_next = mesh_current
else:
mesh_next = __extract_force_field_mesh(object_name, frameno + 1)
return mesh_previous, mesh_current, mesh_next
def __extract_animated_frame_curve_meshes(object_name, frameno):
mesh_current = __extract_force_field_mesh(object_name, frameno)
if frameno - 1 < 0 or not __animated_curve_exists(object_name, frameno - 1):
mesh_previous = mesh_current
else:
mesh_previous = __extract_force_field_mesh(object_name, frameno - 1)
if not __animated_curve_exists(object_name, frameno + 1):
mesh_next = mesh_current
else:
mesh_next = __extract_force_field_mesh(object_name, frameno + 1)
return mesh_previous, mesh_current, mesh_next
def __extract_dynamic_frame_meshes(object_name, frameno):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
motion_type = geometry_database.get_object_motion_export_type(name_slug)
if motion_type == 'KEYFRAMED':
return __extract_keyframed_frame_meshes(object_name, frameno)
elif motion_type == 'ANIMATED':
return __extract_animated_frame_meshes(object_name, frameno)
def __extract_dynamic_force_field_frame_meshes(object_name, frameno):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
motion_type = geometry_database.get_object_motion_export_type(name_slug)
export_dict = geometry_database.get_object_geometry_export_types(name_slug)
if export_dict['mesh']:
if motion_type == 'KEYFRAMED':
return __extract_keyframed_frame_meshes(object_name, frameno)
elif motion_type == 'ANIMATED':
return __extract_animated_frame_meshes(object_name, frameno)
elif export_dict['centroid']:
if motion_type == 'KEYFRAMED':
return __extract_keyframed_frame_centroid_meshes(object_name, frameno)
elif motion_type == 'ANIMATED':
return __extract_animated_frame_centroid_meshes(object_name, frameno)
elif export_dict['curve']:
if motion_type == 'KEYFRAMED':
return __extract_keyframed_frame_curve_meshes(object_name, frameno)
elif motion_type == 'ANIMATED':
return __extract_animated_frame_curve_meshes(object_name, frameno)
def __extract_local_axis(object_name, frameno=0):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
motion_type = geometry_database.get_object_motion_export_type(name_slug)
if motion_type == 'STATIC':
local_x, local_y, local_z = geometry_database.get_axis_static(name_slug)
elif motion_type == 'KEYFRAMED':
local_x, local_y, local_z = geometry_database.get_axis_keyframed(name_slug, frameno)
elif motion_type == 'ANIMATED':
local_x, local_y, local_z = geometry_database.get_axis_animated(name_slug, frameno)
return local_x, local_y, local_z
def __keyframed_mesh_exists(object_name, frameno):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
return geometry_database.mesh_keyframed_exists(name_slug, frameno)
def __animated_mesh_exists(object_name, frameno):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
return geometry_database.mesh_animated_exists(name_slug, frameno)
def __keyframed_centroid_exists(object_name, frameno):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
return geometry_database.centroid_keyframed_exists(name_slug, frameno)
def __animated_centroid_exists(object_name, frameno):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
return geometry_database.centroid_animated_exists(name_slug, frameno)
def __extract_centroid(object_name, frameno):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
motion_type = geometry_database.get_object_motion_export_type(name_slug)
if motion_type == 'STATIC':
centroid = geometry_database.get_centroid_static(name_slug)
elif motion_type == 'KEYFRAMED':
centroid = geometry_database.get_centroid_keyframed(name_slug, frameno)
elif motion_type == 'ANIMATED':
centroid = geometry_database.get_centroid_animated(name_slug, frameno)
data = __get_simulation_data()
scale = data.domain_data.initialize.scale
bbox = data.domain_data.initialize.bbox
centroid[0] = (centroid[0] - bbox.x) * scale
centroid[1] = (centroid[1] - bbox.y) * scale
centroid[2] = (centroid[2] - bbox.z) * scale
return centroid
def __keyframed_curve_exists(object_name, frameno):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
return geometry_database.curve_keyframed_exists(name_slug, frameno)
def __animated_curve_exists(object_name, frameno):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
return geometry_database.curve_animated_exists(name_slug, frameno)
def __extract_curve_mesh(object_name, frameno=0):
name_slug = __get_name_slug(object_name)
geometry_database = __get_geometry_database()
motion_type = geometry_database.get_object_motion_export_type(name_slug)
if motion_type == 'STATIC':
bobj_data = geometry_database.get_curve_static(name_slug)
elif motion_type == 'KEYFRAMED':
bobj_data = geometry_database.get_curve_static(name_slug)
matrix_coefficients = geometry_database.get_curve_keyframed_transform(name_slug, frameno)
elif motion_type == 'ANIMATED':
bobj_data = geometry_database.get_curve_animated(name_slug, frameno)
data = __get_simulation_data()
scale = data.domain_data.initialize.scale
bbox = data.domain_data.initialize.bbox
curve_tmesh = TriangleMesh.from_bobj(bobj_data)
if motion_type == 'KEYFRAMED':
curve_tmesh.apply_transform(matrix_coefficients)
curve_tmesh.translate(-bbox.x, -bbox.y, -bbox.z)
curve_tmesh.scale(scale)
return curve_tmesh
def __extract_data(data_filepath):
with open(data_filepath, 'r', encoding='utf-8') as f:
json_data = json.loads(f.read())
data = flip_fluid_map.Map(json_data)
return data
def __set_output_directories(cache_dir):
cache_directories = [
os.path.join(cache_dir, "bakefiles"),
os.path.join(cache_dir, "logs"),
os.path.join(cache_dir, "savestates"),
os.path.join(cache_dir, "temp")
]
for d in cache_directories:
if not os.path.exists(d):
os.makedirs(d)
def __check_bake_cancelled(bakedata):
if bakedata.is_cancelled or not bake_operators.is_bake_operator_running():
bakedata.is_finished = True
return True
return False
def __get_parameter_data(parameter, frameno=0, value_min=None, value_max=None):
if parameter is None:
raise IndexError()
if hasattr(parameter, 'data') and hasattr(parameter, 'is_animated'):
if parameter.is_animated:
value = parameter.data[frameno]
else:
value = parameter.data
else:
value = parameter
if value_min is not None:
value = max(value, value_min)
if value_max is not None:
value = min(value, value_max)
return value
def __get_limit_behaviour_enum(b):
if b == 'BEHAVIOUR_KILL':
return 0
if b == 'BEHAVIOUR_BALLISTIC':
return 1
if b == 'BEHAVIOUR_COLLIDE':
return 2
return int(b)
def __get_emission_boundary(settings, fluidsim):
dims = fluidsim.get_simulation_dimensions()
bounds = AABB(0.0, 0.0, 0.0, dims.x, dims.y, dims.z)
generate_near_boundary = \
__get_parameter_data(settings.enable_whitewater_emission_near_boundary)
if not generate_near_boundary:
pad_cells = 3.5
pad = pad_cells * fluidsim.get_cell_size()
bounds.expand(-2*pad)
return bounds
def __get_obstacle_meshing_offset(obstacle_meshing_mode):
if type(obstacle_meshing_mode) == float:
if obstacle_meshing_mode == 0.0:
obstacle_meshing_mode = 'MESHING_MODE_INSIDE_SURFACE'
elif obstacle_meshing_mode == 1.0:
obstacle_meshing_mode = 'MESHING_MODE_ON_SURFACE'
elif obstacle_meshing_mode == 2.0:
obstacle_meshing_mode = 'MESHING_MODE_OUTSIDE_SURFACE'
if obstacle_meshing_mode == 'MESHING_MODE_INSIDE_SURFACE':
return 0.25
elif obstacle_meshing_mode == 'MESHING_MODE_ON_SURFACE':
return 0.0
elif obstacle_meshing_mode == 'MESHING_MODE_OUTSIDE_SURFACE':
return -0.5
def __get_viscosity_value(world_data, frameno):
base = __get_parameter_data(world_data.viscosity, frameno)
exp = __get_parameter_data(world_data.viscosity_exponent, frameno)
viscosity = max(base * (10**(-exp)), 0.0)
return viscosity
def __get_surface_tension_value(world_data, frameno):
base = __get_parameter_data(world_data.surface_tension, frameno)
exp = __get_parameter_data(world_data.surface_tension_exponent, frameno)
value = world_data.native_surface_tension_scale * base * (10**(-exp))
return max(value, 0.0)
def __read_save_state_file_data(file_data_path, start_byte, end_byte):
with open(file_data_path, 'rb') as f:
f.seek(start_byte)
data = f.read(end_byte - start_byte)
return data
def __write_save_state_file_data(file_data_path, data, is_appending_data=False):
write_mode = 'wb'
if is_appending_data:
write_mode = 'ab'
with open(file_data_path, write_mode) as f:
f.write(data)
def __load_save_state_marker_particle_data(fluidsim, save_state_directory, autosave_info, data):
num_particles = autosave_info['num_marker_particles']
if num_particles == 0:
return
d = save_state_directory
position_data_file = os.path.join(d, autosave_info['marker_particle_position_filedata'])
velocity_data_file = os.path.join(d, autosave_info['marker_particle_velocity_filedata'])
velocity_transfer_method = data.domain_data.advanced.velocity_transfer_method.data
is_apic_enabled = velocity_transfer_method == 'VELOCITY_TRANSFER_METHOD_APIC'
load_apic_data = False
if is_apic_enabled:
is_apic_data_available = ('marker_particle_affinex_filedata' in autosave_info and
'marker_particle_affiney_filedata' in autosave_info and
'marker_particle_affinez_filedata' in autosave_info)
is_apic_data_available = (is_apic_data_available and
autosave_info['marker_particle_affinex_filedata'] and
autosave_info['marker_particle_affiney_filedata'] and
autosave_info['marker_particle_affinez_filedata'])
if is_apic_data_available:
affinex_data_file = os.path.join(d, autosave_info['marker_particle_affinex_filedata'])
affiney_data_file = os.path.join(d, autosave_info['marker_particle_affiney_filedata'])
affinez_data_file = os.path.join(d, autosave_info['marker_particle_affinez_filedata'])
load_apic_data = True
is_age_attribute_enabled = (data.domain_data.surface.enable_age_attribute.data or
data.domain_data.particles.enable_fluid_particle_age_attribute.data)
load_age_data = False
if is_age_attribute_enabled:
age_path = 'marker_particle_age_filedata'
is_age_data_available = (age_path in autosave_info) and autosave_info[age_path]
if is_age_data_available:
age_data_file = os.path.join(d, autosave_info['marker_particle_age_filedata'])
load_age_data = True
is_lifetime_attribute_enabled = (data.domain_data.surface.enable_lifetime_attribute.data or
data.domain_data.particles.enable_fluid_particle_lifetime_attribute.data)
load_lifetime_data = False
if is_lifetime_attribute_enabled:
lifetime_path = 'marker_particle_lifetime_filedata'
is_lifetime_data_available = (lifetime_path in autosave_info) and autosave_info[lifetime_path]
if is_lifetime_data_available:
lifetime_data_file = os.path.join(d, autosave_info['marker_particle_lifetime_filedata'])
load_lifetime_data = True
is_color_attribute_enabled = (data.domain_data.surface.enable_color_attribute.data or
data.domain_data.particles.enable_fluid_particle_color_attribute.data)
load_color_data = False
if is_color_attribute_enabled:
color_path = 'marker_particle_color_filedata'
is_color_data_available = (color_path in autosave_info) and autosave_info[color_path]
if is_color_data_available:
color_data_file = os.path.join(d, autosave_info['marker_particle_color_filedata'])
load_color_data = True
is_source_id_attribute_enabled = (data.domain_data.surface.enable_source_id_attribute.data or
data.domain_data.particles.enable_fluid_particle_source_id_attribute.data)
load_source_id_data = False
if is_source_id_attribute_enabled:
source_id_path = 'marker_particle_source_id_filedata'
is_source_id_data_available = (source_id_path in autosave_info) and autosave_info[source_id_path]
if is_source_id_data_available:
source_id_data_file = os.path.join(d, autosave_info['marker_particle_source_id_filedata'])
load_source_id_data = True
is_uid_attribute_enabled = data.domain_data.particles.enable_fluid_particle_uid_attribute.data
load_uid_data = False
if is_uid_attribute_enabled:
uid_path = 'marker_particle_uid_filedata'
is_uid_data_available = (uid_path in autosave_info) and autosave_info[uid_path]
if is_uid_data_available:
uid_data_file = os.path.join(d, autosave_info['marker_particle_uid_filedata'])
load_uid_data = True
is_viscosity_attribute_enabled = data.domain_data.surface.enable_viscosity_attribute.data
load_viscosity_data = False
if is_viscosity_attribute_enabled:
viscosity_path = 'marker_particle_viscosity_filedata'
is_viscosity_data_available = (viscosity_path in autosave_info) and autosave_info[viscosity_path]
if is_viscosity_data_available:
viscosity_data_file = os.path.join(d, autosave_info['marker_particle_viscosity_filedata'])
load_viscosity_data = True
is_density_attribute_enabled = data.domain_data.world.enable_density_attribute.data
load_density_data = False
if is_density_attribute_enabled:
density_path = 'marker_particle_density_filedata'
is_density_data_available = (density_path in autosave_info) and autosave_info[density_path]
if is_density_data_available:
density_data_file = os.path.join(d, autosave_info['marker_particle_density_filedata'])
load_density_data = True
is_id_attribute_enabled = data.domain_data.particles.enable_fluid_particle_output.data
load_id_data = False
if is_id_attribute_enabled:
id_path = 'marker_particle_id_filedata'
is_id_data_available = (id_path in autosave_info) and autosave_info[id_path]
if is_id_data_available:
id_data_file = os.path.join(d, autosave_info['marker_particle_id_filedata'])
load_id_data = True
particles_per_read = 2**21
bytes_per_vector = 12
bytes_per_float = 4
bytes_per_int = 4
bytes_per_ulong_long_int = 8
bytes_per_short = 2
max_vector_byte = bytes_per_vector * num_particles
max_float_byte = bytes_per_float * num_particles
max_int_byte = bytes_per_int * num_particles
max_ulong_long_int_byte = bytes_per_ulong_long_int * num_particles
max_short_byte = bytes_per_short * num_particles
num_reads = int((num_particles // particles_per_read) + 1)
for i in range(num_reads):
start_vector_byte = i * bytes_per_vector * particles_per_read
start_float_byte = i * bytes_per_float * particles_per_read
start_int_byte = i * bytes_per_int * particles_per_read
start_ulong_long_int_byte = i * bytes_per_ulong_long_int * particles_per_read
start_short_byte = i * bytes_per_short * particles_per_read
end_vector_byte = min((i + 1) * bytes_per_vector * particles_per_read, max_vector_byte)
end_float_byte = min((i + 1) * bytes_per_float * particles_per_read, max_float_byte)
end_int_byte = min((i + 1) * bytes_per_int * particles_per_read, max_int_byte)
end_ulong_long_int_byte = min((i + 1) * bytes_per_ulong_long_int * particles_per_read, max_ulong_long_int_byte)
end_short_byte = min((i + 1) * bytes_per_short * particles_per_read, max_short_byte)
particle_count = int((end_vector_byte - start_vector_byte) // bytes_per_vector)
position_data = __read_save_state_file_data(position_data_file, start_vector_byte, end_vector_byte)
velocity_data = __read_save_state_file_data(velocity_data_file, start_vector_byte, end_vector_byte)
fluidsim.load_marker_particle_data(particle_count, position_data, velocity_data)
if load_apic_data:
affinex_data = __read_save_state_file_data(affinex_data_file, start_vector_byte, end_vector_byte)
affiney_data = __read_save_state_file_data(affiney_data_file, start_vector_byte, end_vector_byte)
affinez_data = __read_save_state_file_data(affinez_data_file, start_vector_byte, end_vector_byte)
fluidsim.load_marker_particle_affine_data(particle_count, affinex_data, affiney_data, affinez_data)
if load_age_data:
age_data = __read_save_state_file_data(age_data_file, start_float_byte, end_float_byte)
fluidsim.load_marker_particle_age_data(particle_count, age_data)
if load_lifetime_data:
lifetime_data = __read_save_state_file_data(lifetime_data_file, start_float_byte, end_float_byte)
fluidsim.load_marker_particle_lifetime_data(particle_count, lifetime_data)
if load_color_data:
color_data = __read_save_state_file_data(color_data_file, start_vector_byte, end_vector_byte)
fluidsim.load_marker_particle_color_data(particle_count, color_data)
if load_source_id_data:
source_id_data = __read_save_state_file_data(source_id_data_file, start_int_byte, end_int_byte)
fluidsim.load_marker_particle_source_id_data(particle_count, source_id_data)
if load_uid_data:
uid_data = __read_save_state_file_data(uid_data_file, start_int_byte, end_int_byte)
fluidsim.load_marker_particle_uid_data(particle_count, uid_data)
if load_viscosity_data:
viscosity_data = __read_save_state_file_data(viscosity_data_file, start_float_byte, end_float_byte)
fluidsim.load_marker_particle_viscosity_data(particle_count, viscosity_data)
if load_density_data:
density_data = __read_save_state_file_data(density_data_file, start_float_byte, end_float_byte)
fluidsim.load_marker_particle_density_data(particle_count, density_data)
if load_id_data:
id_data = __read_save_state_file_data(id_data_file, start_short_byte, end_short_byte)
fluidsim.load_marker_particle_id_data(particle_count, id_data)
def __load_save_state_diffuse_particle_data(fluidsim, save_state_directory, autosave_info):
num_particles = autosave_info['num_diffuse_particles']
if num_particles == 0:
return
d = save_state_directory
position_data_file = os.path.join(d, autosave_info['diffuse_particle_position_filedata'])
velocity_data_file = os.path.join(d, autosave_info['diffuse_particle_velocity_filedata'])
lifetime_data_file = os.path.join(d, autosave_info['diffuse_particle_lifetime_filedata'])
type_data_file = os.path.join(d, autosave_info['diffuse_particle_type_filedata'])
id_data_file = os.path.join(d, autosave_info['diffuse_particle_id_filedata'])
particles_per_read = 2**21
bytes_per_vector = 12
bytes_per_lifetime = 4
bytes_per_type = 1
bytes_per_id = 1
max_byte_vector = bytes_per_vector * num_particles
max_byte_lifetime = bytes_per_lifetime * num_particles
max_byte_type = bytes_per_type * num_particles
max_byte_id = bytes_per_id * num_particles
num_reads = int((num_particles // particles_per_read) + 1)
for i in range(num_reads):
start_byte = i * bytes_per_vector * particles_per_read
end_byte = min((i + 1) * bytes_per_vector * particles_per_read, max_byte_vector)
particle_count = int((end_byte - start_byte) // bytes_per_vector)
position_data = __read_save_state_file_data(position_data_file, start_byte, end_byte)
velocity_data = __read_save_state_file_data(velocity_data_file, start_byte, end_byte)
start_byte = i * bytes_per_lifetime * particles_per_read
end_byte = min((i + 1) * bytes_per_lifetime * particles_per_read, max_byte_lifetime)
lifetime_data = __read_save_state_file_data(lifetime_data_file, start_byte, end_byte)
start_byte = i * bytes_per_type * particles_per_read
end_byte = min((i + 1) * bytes_per_type * particles_per_read, max_byte_type)
type_data = __read_save_state_file_data(type_data_file, start_byte, end_byte)
start_byte = i * bytes_per_id * particles_per_read
end_byte = min((i + 1) * bytes_per_id * particles_per_read, max_byte_id)
id_data = __read_save_state_file_data(id_data_file, start_byte, end_byte)
fluidsim.load_diffuse_particle_data(particle_count, position_data, velocity_data,
lifetime_data, type_data, id_data)
def __load_save_state_simulator_data(fluidsim, autosave_info):
next_frame = autosave_info["frame_id"] + 1
fluidsim.set_current_frame(next_frame)
if "current_fluid_particle_uid" in autosave_info:
current_uid = int(autosave_info["current_fluid_particle_uid"])
fluidsim.set_current_fluid_particle_uid(current_uid)
def __delete_outdated_savestates(cache_directory, savestate_id):
savestate_directory = os.path.join(cache_directory, "savestates")
subdirs = [d for d in os.listdir(savestate_directory) if os.path.isdir(os.path.join(savestate_directory, d)) ]
if "autosave" in subdirs:
subdirs.remove("autosave")
extensions = [".state", ".data"]
for d in subdirs:
try:
savestate_number = int(d[-6:])
if savestate_number < 0:
continue
except ValueError:
continue
if savestate_number > savestate_id:
path = os.path.join(savestate_directory, d)
try:
fpl.delete_files_in_directory(
path, extensions,
remove_directory=True,
display_popup_on_error=False
)
except:
print("Error: unable to delete directory <" + path + "> (skipping)")
def __delete_outdated_meshes(cache_directory, savestate_id):
bakefiles_directory = os.path.join(cache_directory, "bakefiles")
files = os.listdir(bakefiles_directory)
for f in files:
filename = f.split(".")[0]
try:
filenum = int(filename[-6:])
except ValueError:
continue
if filenum > savestate_id:
path = os.path.join(bakefiles_directory, f)
try:
fpl.delete_file(path)
except:
print("Error: unable to delete file <" + path + "> (skipping)")
stats_filepath = os.path.join(cache_directory, "flipstats.data")
with open(stats_filepath, 'r', encoding='utf-8') as f:
stats_info = json.loads(f.read())
for key in stats_info.copy().keys():
if int(key) > savestate_id:
del stats_info[key]
stats_json = json.dumps(stats_info, sort_keys=True, indent=4)
with open(stats_filepath, 'w', encoding='utf-8') as f:
f.write(stats_json)
def __load_save_state_data(fluidsim, data, cache_directory, savestate_id):
if savestate_id is None:
return
savestate_directory = os.path.join(cache_directory, "savestates")
savestate_name = "autosave" + str(savestate_id).zfill(6)
autosave_directory = os.path.join(savestate_directory, savestate_name)
if not os.path.isdir(autosave_directory):
savestate_name = "autosave"
autosave_directory = os.path.join(savestate_directory, savestate_name)
if not os.path.isdir(autosave_directory):
return
autosave_info_file = os.path.join(autosave_directory, "autosave.state")
if not os.path.isfile(autosave_info_file):
return
with open(autosave_info_file, 'r', encoding='utf-8') as f:
autosave_info = json.loads(f.read())
__load_save_state_marker_particle_data(fluidsim, autosave_directory, autosave_info, data)
__load_save_state_diffuse_particle_data(fluidsim, autosave_directory, autosave_info)
__load_save_state_simulator_data(fluidsim, autosave_info)
init_data = data.domain_data.initialize
if init_data.delete_outdated_savestates:
__delete_outdated_savestates(cache_directory, autosave_info["frame"])
# Replace autosave directory with most current savestate_id directory
current_autosave_directory = os.path.join(savestate_directory, "autosave")
if savestate_name != "autosave" and os.path.isdir(current_autosave_directory):
backup_autosave_directory = current_autosave_directory + ".backup"
if os.path.isdir(backup_autosave_directory):
# Backup autosave directory may already exist from a previous bake, remove if so
fpl.delete_files_in_directory(
backup_autosave_directory, [".state", ".data"],
remove_directory=True,
display_popup_on_error=False
)
os.rename(current_autosave_directory, backup_autosave_directory)
try:
old_directory = autosave_directory
new_directory = os.path.join(savestate_directory, "autosave")
shutil.copytree(old_directory, new_directory, dirs_exist_ok=True)
fpl.delete_files_in_directory(
backup_autosave_directory, [".state", ".data"],
remove_directory=True,
display_popup_on_error=False
)
except Exception as e:
try:
os.rename(backup_autosave_directory, current_autosave_directory)
except FileNotFoundError:
pass
raise
if init_data.delete_outdated_meshes:
__delete_outdated_meshes(cache_directory, autosave_info["frame"])
def __initialize_fluid_simulation_settings(fluidsim, data):
dprops = data.domain_data
frameno = fluidsim.get_current_frame()
# Domain Settings
init_data = data.domain_data.initialize
fluidsim.set_timeline_frame_start(init_data.frame_start)
fluidsim.set_timeline_frame_end(init_data.frame_end)
fluidsim.enable_preview_mesh_output = dprops.initialize.preview_dx
if dprops.initialize.upscale_simulation:
save_isize = dprops.initialize.savestate_isize
save_jsize = dprops.initialize.savestate_jsize
save_ksize = dprops.initialize.savestate_ksize
save_dx = dprops.initialize.savestate_dx
fluidsim.upscale_on_initialization(save_isize, save_jsize, save_ksize, save_dx)
bbox = dprops.initialize.bbox
fluidsim.set_domain_offset(bbox.x, bbox.y, bbox.z)
fluidsim.set_domain_scale(1.0 / dprops.initialize.scale)
fluid_boundary_collisions = __get_parameter_data(dprops.simulation.fluid_boundary_collisions, frameno)
fluidsim.fluid_boundary_collisions = fluid_boundary_collisions
open_boundary_width = __get_parameter_data(dprops.simulation.fluid_open_boundary_width, frameno)
fluidsim.fluid_open_boundary_width = open_boundary_width
# Whitewater Simulation Settings
whitewater = dprops.whitewater
is_whitewater_enabled = __get_parameter_data(whitewater.enable_whitewater_simulation, frameno)
fluidsim.enable_diffuse_material_output = is_whitewater_enabled
if is_whitewater_enabled:
is_foam_enabled = __get_parameter_data(whitewater.enable_foam, frameno)
is_bubbles_enabled = __get_parameter_data(whitewater.enable_bubbles, frameno)
is_spray_enabled = __get_parameter_data(whitewater.enable_spray, frameno)
is_dust_enabled = __get_parameter_data(whitewater.enable_dust, frameno)
is_dust_boundary_emission_enabled = __get_parameter_data(whitewater.enable_dust_emission_near_boundary, frameno)
fluidsim.enable_diffuse_foam = is_foam_enabled
fluidsim.enable_diffuse_bubbles = is_bubbles_enabled
fluidsim.enable_diffuse_spray = is_spray_enabled
fluidsim.enable_diffuse_dust = is_dust_enabled
fluidsim.enable_boundary_diffuse_dust_emission = is_dust_boundary_emission_enabled
fluidsim.enable_whitewater_motion_blur = \
__get_parameter_data(whitewater.generate_whitewater_motion_blur_data, frameno)
fluidsim.enable_whitewater_velocity_attribute = \
__get_parameter_data(whitewater.enable_velocity_vector_attribute, frameno)
fluidsim.enable_whitewater_id_attribute = \
__get_parameter_data(whitewater.enable_id_attribute, frameno)
fluidsim.enable_whitewater_lifetime_attribute = \
__get_parameter_data(whitewater.enable_lifetime_attribute, frameno)
is_generating_whitewater = __get_parameter_data(whitewater.enable_whitewater_emission, frameno)
fluidsim.enable_diffuse_particle_emission = is_generating_whitewater
emitter_pct = __get_parameter_data(whitewater.whitewater_emitter_generation_rate, frameno)
fluidsim.diffuse_emitter_generation_rate = emitter_pct / 100
wavecrest_rate = __get_parameter_data(whitewater.wavecrest_emission_rate, frameno)
turbulence_rate = __get_parameter_data(whitewater.turbulence_emission_rate, frameno)
dust_rate = __get_parameter_data(whitewater.dust_emission_rate, frameno)
fluidsim.diffuse_particle_wavecrest_emission_rate = wavecrest_rate
fluidsim.diffuse_particle_turbulence_emission_rate = turbulence_rate
fluidsim.diffuse_particle_dust_emission_rate = dust_rate
spray_emission_speed = __get_parameter_data(whitewater.spray_emission_speed, frameno)
fluidsim.diffuse_spray_emission_speed = spray_emission_speed
min_speed, max_speed = __get_parameter_data(whitewater.min_max_whitewater_energy_speed, frameno)
fluidsim.min_diffuse_emitter_energy = 0.5 * min_speed * min_speed
fluidsim.max_diffuse_emitter_energy = 0.5 * max_speed * max_speed
mink, maxk = __get_parameter_data(whitewater.min_max_whitewater_wavecrest_curvature, frameno)
fluidsim.min_diffuse_wavecrest_curvature = mink
fluidsim.max_diffuse_wavecrest_curvature = maxk
mint, maxt = __get_parameter_data(whitewater.min_max_whitewater_turbulence, frameno)
fluidsim.min_diffuse_turbulence = mint
fluidsim.max_diffuse_turbulence = maxt
max_particles = __get_parameter_data(whitewater.max_whitewater_particles, frameno)
fluidsim.max_num_diffuse_particles = int(max_particles * 1e6)
bbox = __get_emission_boundary(whitewater, fluidsim)
fluidsim.diffuse_emitter_generation_bounds = bbox
min_lifespan, max_lifespan = __get_parameter_data(whitewater.min_max_whitewater_lifespan, frameno)
lifespan_variance = __get_parameter_data(whitewater.whitewater_lifespan_variance, frameno)
fluidsim.min_diffuse_particle_lifetime = min_lifespan
fluidsim.max_diffuse_particle_lifetime = max_lifespan
fluidsim.diffuse_particle_lifetime_variance = lifespan_variance
foam_modifier = __get_parameter_data(whitewater.foam_lifespan_modifier, frameno)
bubble_modifier = __get_parameter_data(whitewater.bubble_lifespan_modifier, frameno)
spray_modifier = __get_parameter_data(whitewater.spray_lifespan_modifier, frameno)
dust_modifier = __get_parameter_data(whitewater.dust_lifespan_modifier, frameno)
fluidsim.foam_particle_lifetime_modifier = 1.0 / max(foam_modifier, 1e-6)
fluidsim.bubble_particle_lifetime_modifier = 1.0 / max(bubble_modifier, 1e-6)
fluidsim.spray_particle_lifetime_modifier = 1.0 / max(spray_modifier, 1e-6)
fluidsim.dust_particle_lifetime_modifier = 1.0 / max(dust_modifier, 1e-6)
boundary_collisions_mode = __get_parameter_data(whitewater.whitewater_boundary_collisions_mode, frameno)
if boundary_collisions_mode == 'BOUNDARY_COLLISIONS_MODE_INHERIT':
fluid_boundary_collisions = __get_parameter_data(dprops.simulation.fluid_boundary_collisions, frameno)
foam_boundary_collisions = fluid_boundary_collisions
bubble_boundary_collisions = fluid_boundary_collisions
spray_boundary_collisions = fluid_boundary_collisions
dust_boundary_collisions = fluid_boundary_collisions
else:
foam_boundary_collisions = __get_parameter_data(whitewater.foam_boundary_collisions, frameno)
bubble_boundary_collisions = __get_parameter_data(whitewater.bubble_boundary_collisions, frameno)
spray_boundary_collisions = __get_parameter_data(whitewater.spray_boundary_collisions, frameno)
dust_boundary_collisions = __get_parameter_data(whitewater.dust_boundary_collisions, frameno)
fluidsim.foam_boundary_collisions = foam_boundary_collisions
fluidsim.bubble_boundary_collisions = bubble_boundary_collisions
fluidsim.spray_boundary_collisions = spray_boundary_collisions
fluidsim.dust_boundary_collisions = dust_boundary_collisions
"""
foam_behaviour = __get_parameter_data(whitewater.foam_boundary_behaviour, frameno)
bubble_behaviour = __get_parameter_data(whitewater.bubble_boundary_behaviour, frameno)
spray_behaviour = __get_parameter_data(whitewater.spray_boundary_behaviour, frameno)
dust_behaviour = __get_parameter_data(whitewater.bubble_boundary_behaviour, frameno) # Same as bubble for now
foam_behaviour = __get_limit_behaviour_enum(foam_behaviour)
bubble_behaviour = __get_limit_behaviour_enum(bubble_behaviour)
spray_behaviour = __get_limit_behaviour_enum(spray_behaviour)
dust_behaviour = __get_limit_behaviour_enum(dust_behaviour)
fluidsim.diffuse_foam_limit_behaviour = foam_behaviour
fluidsim.diffuse_bubble_limit_behaviour = bubble_behaviour
fluidsim.diffuse_spray_limit_behaviour = spray_behaviour
fluidsim.diffuse_dust_limit_behaviour = dust_behaviour
foam_active_sides = __get_parameter_data(whitewater.foam_boundary_active, frameno)
bubble_active_sides = __get_parameter_data(whitewater.bubble_boundary_active, frameno)
spray_active_sides = __get_parameter_data(whitewater.spray_boundary_active, frameno)
dust_active_sides = __get_parameter_data(whitewater.bubble_boundary_active, frameno) # Same as bubble for now
fluidsim.diffuse_foam_active_boundary_sides = foam_active_sides
fluidsim.diffuse_bubble_active_boundary_sides = bubble_active_sides
fluidsim.diffuse_spray_active_boundary_sides = spray_active_sides
fluidsim.diffuse_dust_active_boundary_sides = dust_active_sides
"""
strength = __get_parameter_data(whitewater.foam_advection_strength, frameno)
foam_depth = __get_parameter_data(whitewater.foam_layer_depth, frameno)
foam_offset = __get_parameter_data(whitewater.foam_layer_offset, frameno)
fluidsim.diffuse_foam_layer_depth = foam_depth
fluidsim.diffuse_foam_layer_offset = foam_offset
fluidsim.diffuse_foam_advection_strength = strength
preserve_foam = __get_parameter_data(whitewater.preserve_foam, frameno)
preserve_rate = __get_parameter_data(whitewater.foam_preservation_rate, frameno)
min_density, max_density = __get_parameter_data(whitewater.min_max_foam_density, frameno)
fluidsim.enable_diffuse_preserve_foam = preserve_foam
fluidsim.diffuse_foam_preservation_rate = preserve_rate
fluidsim.min_diffuse_foam_density = min_density
fluidsim.max_diffuse_foam_density = max_density
drag = __get_parameter_data(whitewater.bubble_drag_coefficient, frameno)
bouyancy = __get_parameter_data(whitewater.bubble_bouyancy_coefficient, frameno)
fluidsim.diffuse_bubble_drag_coefficient = drag
fluidsim.diffuse_bubble_bouyancy_coefficient = bouyancy
drag = __get_parameter_data(whitewater.dust_drag_coefficient, frameno)
bouyancy = __get_parameter_data(whitewater.dust_bouyancy_coefficient, frameno)
fluidsim.diffuse_dust_drag_coefficient = drag
fluidsim.diffuse_dust_bouyancy_coefficient = bouyancy
drag = __get_parameter_data(whitewater.spray_drag_coefficient, frameno)
fluidsim.diffuse_spray_drag_coefficient = drag
base_level = __get_parameter_data(whitewater.obstacle_influence_base_level, frameno)
fluidsim.diffuse_obstacle_influence_base_level = base_level
decay_rate = __get_parameter_data(whitewater.obstacle_influence_decay_rate, frameno)
fluidsim.diffuse_obstacle_influence_decay_rate = decay_rate
# World Settings
world = dprops.world
fluidsim.add_body_force(__get_parameter_data(world.gravity, frameno))
fluidsim.force_field_weight_fluid_particles = __get_parameter_data(world.force_field_weight_fluid_particles, frameno)
fluidsim.force_field_weight_whitewater_foam = __get_parameter_data(world.force_field_weight_whitewater_foam, frameno)
fluidsim.force_field_weight_whitewater_bubble = __get_parameter_data(world.force_field_weight_whitewater_bubble, frameno)
fluidsim.force_field_weight_whitewater_spray = __get_parameter_data(world.force_field_weight_whitewater_spray, frameno)
fluidsim.force_field_weight_whitewater_dust = __get_parameter_data(world.force_field_weight_whitewater_dust, frameno)
# Caches created in older versions may not contain force field data. Ignore these features
# if force field data cannot be found in the cache
is_force_field_data_available = data.force_field_data is not None
if is_force_field_data_available:
force_fields_exist = (len(data.force_field_data) > 0)
is_debugging_force_fields = __get_parameter_data(dprops.debug.export_force_field, frameno)
is_force_fields_enabled = force_fields_exist or is_debugging_force_fields
fluidsim.enable_force_fields = is_force_fields_enabled
if is_force_fields_enabled:
field_quality = __get_parameter_data(world.force_field_resolution, frameno)
if field_quality == 'FORCE_FIELD_RESOLUTION_LOW':
reduction = 4
elif field_quality == 'FORCE_FIELD_RESOLUTION_NORMAL':
reduction = 3
elif field_quality == 'FORCE_FIELD_RESOLUTION_HIGH':
reduction = 2
elif field_quality == 'FORCE_FIELD_RESOLUTION_ULTRA':
reduction = 1
fluidsim.force_field_reduction_level = reduction
is_viscosity_enabled = __get_parameter_data(world.enable_viscosity, frameno)
if is_viscosity_enabled:
surface = dprops.surface
is_variable_viscosity_enabled = __get_parameter_data(surface.enable_viscosity_attribute, frameno)
if is_variable_viscosity_enabled:
fluidsim.viscosity = 0.0
else:
fluidsim.viscosity = __get_viscosity_value(world, frameno)
tolerance_int = __get_parameter_data(world.viscosity_solver_error_tolerance, frameno)
fluidsim.viscosity_solver_error_tolerance = 1.0 * 10.0**(-tolerance_int)
is_surface_tension_enabled = __get_parameter_data(world.enable_surface_tension, frameno)
if is_surface_tension_enabled:
surface_tension = __get_surface_tension_value(world, frameno)
fluidsim.surface_tension = surface_tension
mincfl, maxcfl = world.minimum_surface_tension_cfl, world.maximum_surface_tension_cfl
accuracy_pct = __get_parameter_data(world.surface_tension_accuracy, frameno) / 100.0
surface_tension_number = mincfl + (1.0 - accuracy_pct) * (maxcfl - mincfl)
fluidsim.surface_tension_condition_number = surface_tension_number
is_sheet_seeding_enabled = __get_parameter_data(world.enable_sheet_seeding, frameno)
fluidsim.enable_sheet_seeding = is_sheet_seeding_enabled
if is_sheet_seeding_enabled:
fluidsim.sheet_fill_rate = __get_parameter_data(world.sheet_fill_rate, frameno, value_min=0.0, value_max=1.0)
threshold = __get_parameter_data(world.sheet_fill_threshold, frameno, value_min=0.0, value_max=1.0)
fluidsim.sheet_fill_threshold = threshold - 1
friction = __get_parameter_data(world.boundary_friction, frameno, value_min=0.0, value_max=1.0)
fluidsim.boundary_friction = friction
# Fluid Particle Settings
particles = dprops.particles
enable_fluid_particle_output = __get_parameter_data(particles.enable_fluid_particle_output, frameno)
fluidsim.enable_fluid_particle_output = enable_fluid_particle_output
output_amount = max(__get_parameter_data(particles.fluid_particle_output_amount, frameno), 0.0)
fluidsim.fluid_particle_output_amount = output_amount
enable_fluid_particle_surface_output = __get_parameter_data(particles.enable_fluid_particle_surface_output, frameno)
fluidsim.enable_fluid_particle_surface_output = enable_fluid_particle_surface_output
enable_fluid_particle_boundary_output = __get_parameter_data(particles.enable_fluid_particle_boundary_output, frameno)
fluidsim.enable_fluid_particle_boundary_output = enable_fluid_particle_boundary_output
enable_fluid_particle_interior_output = __get_parameter_data(particles.enable_fluid_particle_interior_output, frameno)
fluidsim.enable_fluid_particle_interior_output = enable_fluid_particle_interior_output
source_id = __get_parameter_data(particles.fluid_particle_source_id_blacklist, frameno)
fluidsim.fluid_particle_source_id_blacklist = source_id
enable_velocity_attribute = __get_parameter_data(particles.enable_fluid_particle_velocity_vector_attribute, frameno)
fluidsim.enable_fluid_particle_velocity_attribute = enable_velocity_attribute
enable_speed_attribute = __get_parameter_data(particles.enable_fluid_particle_speed_attribute, frameno)
fluidsim.enable_fluid_particle_speed_attribute = enable_speed_attribute
enable_vorticity_attribute = __get_parameter_data(particles.enable_fluid_particle_vorticity_vector_attribute, frameno)
fluidsim.enable_fluid_particle_vorticity_attribute = enable_vorticity_attribute
enable_color_attribute = __get_parameter_data(particles.enable_fluid_particle_color_attribute, frameno)
fluidsim.enable_fluid_particle_color_attribute = enable_color_attribute
enable_age_attribute = __get_parameter_data(particles.enable_fluid_particle_age_attribute, frameno)
fluidsim.enable_fluid_particle_age_attribute = enable_age_attribute
enable_lifetime_attribute = __get_parameter_data(particles.enable_fluid_particle_lifetime_attribute, frameno)
fluidsim.enable_fluid_particle_lifetime_attribute = enable_lifetime_attribute
enable_proximity_attribute = __get_parameter_data(particles.enable_fluid_particle_whitewater_proximity_attribute, frameno)
fluidsim.enable_fluid_particle_whitewater_proximity_attribute = enable_proximity_attribute
enable_source_id_attribute = __get_parameter_data(particles.enable_fluid_particle_source_id_attribute, frameno)
fluidsim.enable_fluid_particle_source_id_attribute = enable_source_id_attribute
enable_uid_attribute = __get_parameter_data(particles.enable_fluid_particle_uid_attribute, frameno)
fluidsim.enable_fluid_particle_uid_attribute = enable_uid_attribute
reused_uid_attribute = __get_parameter_data(particles.enable_fluid_particle_uid_attribute_reuse, frameno)
fluidsim.enable_fluid_particle_uid_attribute_reuse = reused_uid_attribute
enable_density_attribute = __get_parameter_data(world.enable_density_attribute, frameno)
fluidsim.enable_fluid_particle_density_attribute = enable_density_attribute
# Surface Settings
surface = dprops.surface
enable_surface_mesh_generation = __get_parameter_data(surface.enable_surface_mesh_generation, frameno)
fluidsim.enable_surface_reconstruction = enable_surface_mesh_generation
subdivisions = __get_parameter_data(surface.subdivisions, frameno) + 1
fluidsim.surface_subdivision_level = subdivisions
compute_chunk_mode = __get_parameter_data(surface.compute_chunk_mode, frameno)
if compute_chunk_mode == 'COMPUTE_CHUNK_MODE_AUTO':
num_chunks = __get_parameter_data(surface.compute_chunks_auto, frameno)
elif compute_chunk_mode == 'COMPUTE_CHUNK_MODE_FIXED':
num_chunks = __get_parameter_data(surface.compute_chunks_fixed, frameno)
fluidsim.num_polygonizer_slices = num_chunks
particle_scale = __get_parameter_data(surface.particle_scale, frameno)
particle_scale *= surface.native_particle_scale
fluidsim.marker_particle_scale = particle_scale
fluidsim.surface_smoothing_value = __get_parameter_data(surface.smoothing_value, frameno)
fluidsim.surface_smoothing_iterations = __get_parameter_data(surface.smoothing_iterations, frameno)
enable_meshing_offset = __get_parameter_data(surface.enable_meshing_offset, frameno)
fluidsim.enable_obstacle_meshing_offset = enable_meshing_offset
meshing_mode = __get_parameter_data(surface.obstacle_meshing_mode, frameno)
meshing_offset = __get_obstacle_meshing_offset(meshing_mode)
fluidsim.obstacle_meshing_offset = meshing_offset
fluidsim.enable_remove_surface_near_domain = __get_parameter_data(surface.remove_mesh_near_domain, frameno)
fluidsim.remove_surface_near_domain_distance = __get_parameter_data(surface.remove_mesh_near_domain_distance, frameno) - 1
domain_sides = __get_parameter_data(surface.remove_mesh_near_domain_sides, frameno)
fluidsim.remove_surface_near_domain_sides = domain_sides
fluidsim.enable_inverted_contact_normals = __get_parameter_data(surface.invert_contact_normals, frameno)
fluidsim.enable_surface_motion_blur = __get_parameter_data(surface.generate_motion_blur_data, frameno)
fluidsim.enable_surface_velocity_attribute = __get_parameter_data(surface.enable_velocity_vector_attribute, frameno)
# Option should always be enabled
# fluidsim.enable_surface_velocity_attribute_against_obstacles = \
# __get_parameter_data(surface.enable_velocity_vector_attribute_against_obstacles, frameno)
fluidsim.enable_surface_velocity_attribute_against_obstacles = True
fluidsim.enable_surface_speed_attribute = __get_parameter_data(surface.enable_speed_attribute, frameno)
fluidsim.enable_surface_vorticity_attribute = __get_parameter_data(surface.enable_vorticity_vector_attribute, frameno)
fluidsim.enable_surface_age_attribute = __get_parameter_data(surface.enable_age_attribute, frameno)
fluidsim.surface_age_attribute_radius = __get_parameter_data(surface.age_attribute_radius, frameno)
fluidsim.enable_surface_lifetime_attribute = __get_parameter_data(surface.enable_lifetime_attribute, frameno)
fluidsim.surface_lifetime_attribute_radius = __get_parameter_data(surface.lifetime_attribute_radius, frameno)
fluidsim.surface_lifetime_attribute_death_time = __get_parameter_data(surface.lifetime_attribute_death_time, frameno)
fluidsim.enable_surface_whitewater_proximity_attribute = __get_parameter_data(surface.enable_whitewater_proximity_attribute, frameno)
fluidsim.surface_whitewater_proximity_attribute_radius = __get_parameter_data(surface.whitewater_proximity_attribute_radius, frameno)
fluidsim.enable_surface_color_attribute = __get_parameter_data(surface.enable_color_attribute, frameno)
fluidsim.surface_color_attribute_radius = __get_parameter_data(surface.color_attribute_radius, frameno)
fluidsim.enable_surface_color_attribute_mixing = __get_parameter_data(surface.enable_color_attribute_mixing, frameno)
fluidsim.surface_color_attribute_mixing_rate = __get_parameter_data(surface.color_attribute_mixing_rate, frameno)
fluidsim.surface_color_attribute_mixing_radius = __get_parameter_data(surface.color_attribute_mixing_radius, frameno)
if fluidsim.enable_surface_color_attribute_mixing:
mixing_mode = __get_parameter_data(surface.color_attribute_mixing_mode, frameno)
if mixing_mode == 'COLOR_MIXING_MODE_MIXBOX':
__initialize_mixbox(fluidsim)
fluidsim.enable_mixbox = True
else:
fluidsim.enable_mixbox = False
fluidsim.enable_surface_source_id_attribute = __get_parameter_data(surface.enable_source_id_attribute, frameno)
is_viscosity_enabled = __get_parameter_data(world.enable_viscosity, frameno)
if is_viscosity_enabled:
fluidsim.enable_surface_viscosity_attribute = __get_parameter_data(surface.enable_viscosity_attribute, frameno)
fluidsim.enable_surface_density_attribute = __get_parameter_data(world.enable_density_attribute, frameno)
__set_meshing_volume_object(fluidsim, data, frameno)
# Advanced Settings
advanced = dprops.advanced
min_substeps, max_substeps = __get_parameter_data(advanced.min_max_time_steps_per_frame, frameno)
fluidsim.min_time_steps_per_frame = min_substeps
fluidsim.max_time_steps_per_frame = max_substeps
fluidsim.enable_adaptive_obstacle_time_stepping = \
__get_parameter_data(advanced.enable_adaptive_obstacle_time_stepping, frameno)
fluidsim.enable_adaptive_force_field_time_stepping = \
__get_parameter_data(advanced.enable_adaptive_force_field_time_stepping, frameno)
fluidsim.marker_particle_jitter_factor = \
__get_parameter_data(advanced.particle_jitter_factor, frameno)
fluidsim.jitter_surface_marker_particles = \
__get_parameter_data(advanced.jitter_surface_particles, frameno)
fluidsim.pressure_solver_max_iterations = \
__get_parameter_data(advanced.pressure_solver_max_iterations, frameno)
fluidsim.viscosity_solver_max_iterations = \
__get_parameter_data(advanced.viscosity_solver_max_iterations, frameno)
velocity_transfer_method = __get_parameter_data(advanced.velocity_transfer_method, frameno)
if velocity_transfer_method == 'VELOCITY_TRANSFER_METHOD_FLIP':
fluidsim.set_velocity_transfer_method_FLIP()
elif velocity_transfer_method == 'VELOCITY_TRANSFER_METHOD_APIC':
fluidsim.set_velocity_transfer_method_APIC()
fluidsim.PICFLIP_ratio = __get_parameter_data(advanced.PICFLIP_ratio, frameno)
fluidsim.PICAPIC_ratio = __get_parameter_data(advanced.PICAPIC_ratio, frameno)
CFL_number = __get_parameter_data(advanced.CFL_condition_number, frameno)
fluidsim.CFL_condition_number = CFL_number
fluidsim.enable_extreme_velocity_removal = \
__get_parameter_data(advanced.enable_extreme_velocity_removal, frameno)
threading_mode = __get_parameter_data(advanced.threading_mode, frameno)
if threading_mode == 'THREADING_MODE_AUTO_DETECT':
num_threads = __get_parameter_data(advanced.num_threads_auto_detect, frameno)
elif threading_mode == 'THREADING_MODE_FIXED':
num_threads = __get_parameter_data(advanced.num_threads_fixed, frameno)
fluidsim.max_thread_count = num_threads
fluidsim.enable_asynchronous_meshing = \
__get_parameter_data(advanced.enable_asynchronous_meshing, frameno)
fluidsim.enable_fracture_optimization = \
__get_parameter_data(advanced.enable_fracture_optimization, frameno)
fluidsim.enable_static_solid_levelset_precomputation = \
__get_parameter_data(advanced.precompute_static_obstacles, frameno)
fluidsim.enable_temporary_mesh_levelset = \
__get_parameter_data(advanced.reserve_temporary_grids, frameno)
# Debug Settings
fluidsim.enable_fluid_particle_debug_output = \
__get_parameter_data(dprops.debug.enable_fluid_particle_debug_output, frameno)
fluidsim.enable_internal_obstacle_mesh_output = \
__get_parameter_data(dprops.debug.export_internal_obstacle_mesh, frameno)
if is_force_field_data_available:
fluidsim.enable_force_field_debug_output = \
__get_parameter_data(dprops.debug.export_force_field, frameno)
# Internal Settings
fluidsim.set_mesh_output_format_as_bobj()
if is_whitewater_enabled:
fluidsim.output_diffuse_material_as_separate_files = True
def __get_mesh_centroid(tmesh):
vsum = [0.0, 0.0, 0.0]
for i in range(0, len(tmesh.vertices), 3):
vsum[0] += tmesh.vertices[i]
vsum[1] += tmesh.vertices[i + 1]
vsum[2] += tmesh.vertices[i + 2]
vsum[0] /= (len(tmesh.vertices) / 3)
vsum[1] /= (len(tmesh.vertices) / 3)
vsum[2] /= (len(tmesh.vertices) / 3)
return vsum
def __get_fluid_object_velocity(fluid_object, frameid):
if fluid_object.fluid_velocity_mode.data == 'FLUID_VELOCITY_MANUAL':
return __get_parameter_data(fluid_object.initial_velocity, frameid)
elif fluid_object.fluid_velocity_mode.data == 'FLUID_VELOCITY_AXIS':
timeline_frame = __get_timeline_frame()
local_x, local_y, local_z = __extract_local_axis(fluid_object.name, timeline_frame)
axis_mode = __get_parameter_data(fluid_object.fluid_axis_mode, frameid)
if axis_mode == 'LOCAL_AXIS_POS_X' or axis_mode == 0.0:
local_axis = local_x
elif axis_mode == 'LOCAL_AXIS_POS_Y' or axis_mode == 1.0:
local_axis = local_y
elif axis_mode == 'LOCAL_AXIS_POS_Z' or axis_mode == 2.0:
local_axis = local_z
elif axis_mode == 'LOCAL_AXIS_NEG_X' or axis_mode == 3.0:
local_axis = [-local_x[0], -local_x[1], -local_x[2]]
elif axis_mode == 'LOCAL_AXIS_NEG_Y' or axis_mode == 4.0:
local_axis = [-local_y[0], -local_y[1], -local_y[2]]
elif axis_mode == 'LOCAL_AXIS_NEG_Z' or axis_mode == 5.0:
local_axis = [-local_z[0], -local_z[1], -local_z[2]]
initial_speed = __get_parameter_data(fluid_object.initial_speed, frameid)
velocity = [initial_speed * local_axis[0], initial_speed * local_axis[1], initial_speed * local_axis[2]]
return velocity
# Use target
if not fluid_object.target_object:
return [0, 0, 0]
target_object_name = fluid_object.target_object
initial_speed = __get_parameter_data(fluid_object.initial_speed, frameid)
timeline_frame = __get_timeline_frame()
fluid_object_mesh = __extract_mesh(fluid_object.name, timeline_frame)
c1 = __get_mesh_centroid(fluid_object_mesh)
c2 = __extract_centroid(target_object_name, timeline_frame)
vdir = [c2[0] - c1[0], c2[1] - c1[1], c2[2] - c1[2]]
vlen = math.sqrt(vdir[0] * vdir[0] + vdir[1] * vdir[1] + vdir[2] * vdir[2])
eps = 1e-6
if vlen < eps:
return [0, 0, 0]
vdir[0] /= vlen
vdir[1] /= vlen
vdir[2] /= vlen
vdir[0] *= initial_speed
vdir[1] *= initial_speed
vdir[2] *= initial_speed
return vdir
def __get_inflow_object_velocity(inflow_object, frameid):
if inflow_object.inflow_velocity_mode.data == 'INFLOW_VELOCITY_MANUAL':
return __get_parameter_data(inflow_object.inflow_velocity, frameid)
elif inflow_object.inflow_velocity_mode.data == 'INFLOW_VELOCITY_AXIS':
timeline_frame = __get_timeline_frame()
local_x, local_y, local_z = __extract_local_axis(inflow_object.name, timeline_frame)
axis_mode = __get_parameter_data(inflow_object.inflow_axis_mode, frameid)
if axis_mode == 'LOCAL_AXIS_POS_X' or axis_mode == 0.0:
local_axis = local_x
elif axis_mode == 'LOCAL_AXIS_POS_Y' or axis_mode == 1.0:
local_axis = local_y
elif axis_mode == 'LOCAL_AXIS_POS_Z' or axis_mode == 2.0:
local_axis = local_z
elif axis_mode == 'LOCAL_AXIS_NEG_X' or axis_mode == 3.0:
local_axis = [-local_x[0], -local_x[1], -local_x[2]]
elif axis_mode == 'LOCAL_AXIS_NEG_Y' or axis_mode == 4.0:
local_axis = [-local_y[0], -local_y[1], -local_y[2]]
elif axis_mode == 'LOCAL_AXIS_NEG_Z' or axis_mode == 5.0:
local_axis = [-local_z[0], -local_z[1], -local_z[2]]
inflow_speed = __get_parameter_data(inflow_object.inflow_speed, frameid)
velocity = [inflow_speed * local_axis[0], inflow_speed * local_axis[1], inflow_speed * local_axis[2]]
return velocity
# Use target
if not inflow_object.target_object:
return [0, 0, 0]
target_object_name = inflow_object.target_object
inflow_speed = __get_parameter_data(inflow_object.inflow_speed, frameid)
timeline_frame = __get_timeline_frame()
fluid_object_mesh = __extract_mesh(inflow_object.name, timeline_frame)
c1 = __get_mesh_centroid(fluid_object_mesh)
c2 = __extract_centroid(target_object_name, timeline_frame)
vdir = [c2[0] - c1[0], c2[1] - c1[1], c2[2] - c1[2]]
vlen = math.sqrt(vdir[0] * vdir[0] + vdir[1] * vdir[1] + vdir[2] * vdir[2])
eps = 1e-6
if vlen < eps:
return [0, 0, 0]
vdir[0] /= vlen
vdir[1] /= vlen
vdir[2] /= vlen
vdir[0] *= inflow_speed
vdir[1] *= inflow_speed
vdir[2] *= inflow_speed
return vdir
def __add_fluid_objects(fluidsim, data, bakedata, frameid=0):
init_data = data.domain_data.initialize
bbox = init_data.bbox
isize, jsize, ksize = init_data.isize, init_data.jsize, init_data.ksize
dx = init_data.dx
for obj in list(data.fluid_data):
if obj.frame_offset_type.data == 'OFFSET_TYPE_FRAME':
frame_offset = __get_parameter_data(obj.frame_offset, frameid)
if frame_offset != frameid:
continue
elif obj.frame_offset_type.data == 'OFFSET_TYPE_TIMELINE':
frame_offset = __get_parameter_data(obj.timeline_offset, frameid)
if frame_offset != __get_timeline_frame():
continue
fluid_object = MeshObject(isize, jsize, ksize, dx)
if __is_object_dynamic(obj.name):
timeline_frame = __get_timeline_frame()
previous_mesh, current_mesh, next_mesh = __extract_dynamic_frame_meshes(obj.name, timeline_frame)
fluid_object.update_mesh_animated(previous_mesh, current_mesh, next_mesh)
else:
mesh = __extract_static_frame_mesh(obj.name)
fluid_object.update_mesh_static(mesh)
fluid_object.enable_append_object_velocity = __get_parameter_data(obj.append_object_velocity, frameid)
fluid_object.object_velocity_influence = __get_parameter_data(obj.append_object_velocity_influence, frameid)
fluid_object.priority = __get_parameter_data(obj.priority, frameid)
fluid_object.source_id = __get_parameter_data(obj.source_id, frameid)
fluid_object.viscosity = __get_parameter_data(obj.viscosity, frameid)
fluid_object.density = __get_parameter_data(obj.density, frameid)
fluid_object.lifetime = __get_parameter_data(obj.lifetime, frameid)
fluid_object.lifetime_variance = __get_parameter_data(obj.lifetime_variance, frameid)
fluid_object.set_source_color(__get_parameter_data(obj.color, frameid))
velocity = __get_fluid_object_velocity(obj, frameid)
fluidsim.add_mesh_fluid(fluid_object, velocity[0], velocity[1], velocity[2])
data.fluid_data.remove(obj)
if __check_bake_cancelled(bakedata):
return
def __add_obstacle_objects(fluidsim, data, bakedata):
init_data = data.domain_data.initialize
bbox = init_data.bbox
isize, jsize, ksize = init_data.isize, init_data.jsize, init_data.ksize
dx = init_data.dx
obstacle_objects = []
for obj in data.obstacle_data:
obstacle = MeshObject(isize, jsize, ksize, dx)
obstacle.inverse = __get_parameter_data(obj.is_inversed)
if not __is_object_dynamic(obj.name):
mesh = __extract_static_frame_mesh(obj.name)
obstacle.update_mesh_static(mesh)
obstacle_objects.append(obstacle)
fluidsim.add_mesh_obstacle(obstacle)
if __check_bake_cancelled(bakedata):
return
return obstacle_objects
def __add_inflow_objects(fluidsim, data, bakedata):
init_data = data.domain_data.initialize
bbox = init_data.bbox
isize, jsize, ksize = init_data.isize, init_data.jsize, init_data.ksize
dx = init_data.dx
inflow_objects = []
for obj in data.inflow_data:
source = MeshFluidSource(isize, jsize, ksize, dx)
if not __is_object_dynamic(obj.name):
mesh = __extract_static_frame_mesh(obj.name)
source.update_mesh_static(mesh)
fluidsim.add_mesh_fluid_source(source)
inflow_objects.append(source)
if __check_bake_cancelled(bakedata):
return
return inflow_objects
def __add_outflow_objects(fluidsim, data, bakedata):
init_data = data.domain_data.initialize
bbox = init_data.bbox
isize, jsize, ksize = init_data.isize, init_data.jsize, init_data.ksize
dx = init_data.dx
outflow_objects = []
for obj in data.outflow_data:
source = MeshFluidSource(isize, jsize, ksize, dx)
source.outflow = True
source.outflow_inverse = __get_parameter_data(obj.is_inversed)
if not __is_object_dynamic(obj.name):
mesh = __extract_static_frame_mesh(obj.name)
source.update_mesh_static(mesh)
fluidsim.add_mesh_fluid_source(source)
outflow_objects.append(source)
if __check_bake_cancelled(bakedata):
return
return outflow_objects
def __add_force_field_objects(fluidsim, data, bakedata):
force_field_objects = []
if not fluidsim.enable_force_fields:
return force_field_objects
init_data = data.domain_data.initialize
bbox = init_data.bbox
isize, jsize, ksize = init_data.isize, init_data.jsize, init_data.ksize
dx = init_data.dx
force_field_grid = fluidsim.get_force_field_grid()
force_field_objects = []
for obj in data.force_field_data:
field_type = obj.force_field_type.data
field_object = None
if field_type == 'FORCE_FIELD_TYPE_POINT':
field_object = ForceFieldPoint()
elif field_type == 'FORCE_FIELD_TYPE_SURFACE':
field_object = ForceFieldSurface()
elif field_type == 'FORCE_FIELD_TYPE_VOLUME':
field_object = ForceFieldVolume()
elif field_type == 'FORCE_FIELD_TYPE_CURVE':
field_object = ForceFieldCurve()
if not __is_object_dynamic(obj.name):
mesh = __extract_force_field_mesh(obj.name)
field_object.update_mesh_static(mesh)
force_field_grid.add_force_field(field_object)
force_field_objects.append(field_object)
if __check_bake_cancelled(bakedata):
return
return force_field_objects
def __initialize_mixbox(fluidsim):
module_dir = os.path.dirname(os.path.realpath(__file__))
lut_filepath = os.path.join(module_dir, "third_party", "mixbox", "mixbox_lut_data.bin")
if os.path.isfile(lut_filepath):
with open(lut_filepath, 'rb') as f:
lut_data = f.read()
lut_data_bytes = len(lut_data)
mixbox.initialize(lut_data, lut_data_bytes)
# Not necessary to initialize Mixbox again, but this will output data to the simulation log
fluidsim.initialize_mixbox(lut_data, lut_data_bytes)
def __initialize_fluid_simulation(fluidsim, data, cache_directory, bakedata, savestate_id):
set_console_output(bakedata.is_console_output_enabled)
__load_save_state_data(fluidsim, data, cache_directory, savestate_id)
init_data = data.domain_data.initialize
num_frames = init_data.frame_end - init_data.frame_start + 1
bakedata.completed_frames = fluidsim.get_current_frame()
bakedata.progress = bakedata.completed_frames / num_frames
__initialize_fluid_simulation_settings(fluidsim, data)
__add_fluid_objects(fluidsim, data, bakedata, fluidsim.get_current_frame())
data.obstacle_objects = __add_obstacle_objects(fluidsim, data, bakedata)
data.inflow_objects = __add_inflow_objects(fluidsim, data, bakedata)
data.outflow_objects = __add_outflow_objects(fluidsim, data, bakedata)
data.force_field_objects = __add_force_field_objects(fluidsim, data, bakedata)
fluidsim.initialize()
bakedata.is_initialized = True
def __update_dynamic_object_mesh(animated_object, object_data):
timeline_frame = __get_timeline_frame()
mesh_previous, mesh_current, mesh_next = __extract_dynamic_frame_meshes(object_data.name, timeline_frame)
animated_object.update_mesh_animated(mesh_previous, mesh_current, mesh_next)
def __update_dynamic_force_field_mesh(animated_object, object_data):
timeline_frame = __get_timeline_frame()
mesh_previous, mesh_current, mesh_next = __extract_dynamic_force_field_frame_meshes(object_data.name, timeline_frame)
animated_object.update_mesh_animated(mesh_previous, mesh_current, mesh_next)
def __update_animatable_inflow_properties(data, mesh_geometry_data, frameid):
inflow_objects = data.inflow_objects
inflow_data = data.inflow_data
for idx, inflow in enumerate(inflow_objects):
data = inflow_data[idx]
name_slug = __get_name_slug(data.name)
object_geometry_data = mesh_geometry_data[name_slug]
if object_geometry_data["is_motion_dynamic"]:
mesh_previous = object_geometry_data["triangle_mesh_previous"]
mesh_current = object_geometry_data["triangle_mesh_current"]
mesh_next = object_geometry_data["triangle_mesh_next"]
inflow.update_mesh_animated(mesh_previous, mesh_current, mesh_next)
inflow.enable = __get_parameter_data(data.is_enabled, frameid)
inflow.set_velocity(__get_inflow_object_velocity(data, frameid))
inflow.enable_append_object_velocity = \
__get_parameter_data(data.append_object_velocity, frameid)
inflow.object_velocity_influence = \
__get_parameter_data(data.append_object_velocity_influence, frameid)
inflow.substep_emissions = __get_parameter_data(data.substep_emissions, frameid)
inflow.priority = __get_parameter_data(data.priority, frameid)
is_constrained = __get_parameter_data(data.constrain_fluid_velocity, frameid)
inflow.enable_constrained_fluid_velocity = is_constrained
inflow.source_id = __get_parameter_data(data.source_id, frameid)
inflow.viscosity = __get_parameter_data(data.viscosity, frameid)
inflow.density = __get_parameter_data(data.density, frameid)
inflow.lifetime = __get_parameter_data(data.lifetime, frameid)
inflow.lifetime_variance = __get_parameter_data(data.lifetime_variance, frameid)
inflow.set_source_color(__get_parameter_data(data.color, frameid))
def __update_animatable_outflow_properties(data, mesh_geometry_data, frameid):
outflow_objects = data.outflow_objects
outflow_data = data.outflow_data
for idx, outflow in enumerate(outflow_objects):
data = outflow_data[idx]
name_slug = __get_name_slug(data.name)
object_geometry_data = mesh_geometry_data[name_slug]
if object_geometry_data["is_motion_dynamic"]:
mesh_previous = object_geometry_data["triangle_mesh_previous"]
mesh_current = object_geometry_data["triangle_mesh_current"]
mesh_next = object_geometry_data["triangle_mesh_next"]
outflow.update_mesh_animated(mesh_previous, mesh_current, mesh_next)
outflow.enable = __get_parameter_data(data.is_enabled, frameid)
outflow.fluid_outflow = __get_parameter_data(data.remove_fluid, frameid)
outflow.diffuse_outflow = __get_parameter_data(data.remove_whitewater, frameid)
def __update_animatable_force_field_properties(data, frameid):
force_field_objects = data.force_field_objects
force_field_data = data.force_field_data
for idx, force_field in enumerate(force_field_objects):
data = force_field_data[idx]
if __is_object_dynamic(data.name):
__update_dynamic_force_field_mesh(force_field, data)
force_field.enable = __get_parameter_data(data.is_enabled, frameid)
force_field.strength = __get_parameter_data(data.strength, frameid)
force_field.falloff_power = __get_parameter_data(data.falloff_power, frameid)
force_field.max_force_limit_factor = __get_parameter_data(data.maximum_force_limit_factor, frameid)
force_field.enable_min_distance = __get_parameter_data(data.enable_min_distance, frameid)
force_field.enable_max_distance = __get_parameter_data(data.enable_max_distance, frameid)
force_field.min_distance, force_field.max_distance = __get_parameter_data(data.min_max_distance, frameid)
field_type = data.force_field_type.data
if field_type == 'FORCE_FIELD_TYPE_POINT':
force_field.gravity_scale = __get_parameter_data(data.gravity_scale_point, frameid)
force_field.gravity_scale_width = __get_parameter_data(data.gravity_scale_width_point, frameid)
elif field_type == 'FORCE_FIELD_TYPE_SURFACE':
force_field.enable_frontfacing = __get_parameter_data(data.enable_frontfacing, frameid)
force_field.enable_backfacing = __get_parameter_data(data.enable_backfacing, frameid)
force_field.enable_edgefacing = __get_parameter_data(data.enable_edgefacing, frameid)
force_field.gravity_scale = __get_parameter_data(data.gravity_scale_surface, frameid)
force_field.gravity_scale_width = __get_parameter_data(data.gravity_scale_width_surface, frameid)
elif field_type == 'FORCE_FIELD_TYPE_VOLUME':
force_field.gravity_scale = __get_parameter_data(data.gravity_scale_volume, frameid)
force_field.gravity_scale_width = __get_parameter_data(data.gravity_scale_width_volume, frameid)
elif field_type == 'FORCE_FIELD_TYPE_CURVE':
force_field.flow_strength = __get_parameter_data(data.flow_strength, frameid)
force_field.spin_strength = __get_parameter_data(data.spin_strength, frameid)
force_field.enable_endcaps = __get_parameter_data(data.enable_endcaps, frameid)
force_field.gravity_scale = __get_parameter_data(data.gravity_scale_curve, frameid)
force_field.gravity_scale_width = __get_parameter_data(data.gravity_scale_width_curve, frameid)
def __update_animatable_obstacle_properties(data, mesh_geometry_data, frameid):
obstacle_objects = data.obstacle_objects
obstacle_data = data.obstacle_data
#### WORKAROUND ####
# Due to a current design issue in the simulator, if there is a mix of
# static and dynamic inverse obstacles in the simulation, then the combined
# inverse SDF will not be computed correctly. A workaround in previous
# versions of the addon was to enable "Export Animation Mesh" on all inverse
# obstacles so that there was not a mix and the SDF would be computed correctly.
#
# This section automatically applies this workaround by detecting if there
# are any dynamic inverse obstacles, and if so, treating all static inverse
# obstacles as dynamic ones. This is done by using the update_mesh_animated()
# method and supplying the static mesh for all frame_previous, frame_current, and
# frame_next.
#
# In future development, or in the next iteration of the simulator, this should
# be fixed properly inside of the simulation engine.
is_inverse_dynamic = False
for idx, mesh_object in enumerate(obstacle_objects):
data = obstacle_data[idx]
if mesh_object.inverse:
is_inverse_dynamic = is_inverse_dynamic or __is_object_dynamic(data.name)
if is_inverse_dynamic:
for idx, mesh_object in enumerate(obstacle_objects):
data = obstacle_data[idx]
if mesh_object.inverse and not __is_object_dynamic(data.name):
mesh = __extract_static_frame_mesh(data.name)
mesh_object.update_mesh_animated(mesh, mesh, mesh)
#### END WORKAROUND ####
total_update_time = 0.0
start_mesh_object = time.time()
for idx, mesh_object in enumerate(obstacle_objects):
data = obstacle_data[idx]
name_slug = __get_name_slug(data.name)
object_geometry_data = mesh_geometry_data[name_slug]
if object_geometry_data["is_motion_dynamic"]:
mesh_previous = object_geometry_data["triangle_mesh_previous"]
mesh_current = object_geometry_data["triangle_mesh_current"]
mesh_next = object_geometry_data["triangle_mesh_next"]
mesh_object.update_mesh_animated(mesh_previous, mesh_current, mesh_next)
mesh_object.enable = __get_parameter_data(data.is_enabled, frameid)
mesh_object.friction = __get_parameter_data(data.friction, frameid, value_min=0.0)
mesh_object.velocity_scale = __get_parameter_data(data.velocity_scale, frameid)
mesh_object.whitewater_influence = __get_parameter_data(data.whitewater_influence, frameid, value_min=0.0)
mesh_object.dust_emission_strength = __get_parameter_data(data.dust_emission_strength, frameid, value_min=0.0)
mesh_object.sheeting_strength = __get_parameter_data(data.sheeting_strength, frameid, value_min=0.0)
mesh_object.mesh_expansion = __get_parameter_data(data.mesh_expansion, frameid)
def __update_animatable_meshing_volume_properties(data, frameid):
surface_data = data.domain_data.surface
meshing_volume_mode = __get_parameter_data(surface_data.meshing_volume_mode, frameid)
if meshing_volume_mode != 'MESHING_VOLUME_MODE_OBJECT':
return
if not surface_data.meshing_volume_object:
return
volume_object = surface_data.meshing_volume_object_class
volume_name = surface_data.meshing_volume_object
if __is_object_dynamic(surface_data.meshing_volume_object):
timeline_frame = __get_timeline_frame()
mesh_previous, mesh_current, mesh_next = __extract_dynamic_frame_meshes(volume_name, timeline_frame)
volume_object.update_mesh_animated(mesh_previous, mesh_current, mesh_next)
def __set_property(obj, pname, value, value_min=None, value_max=None):
if value_min is not None:
value = max(value, value_min)
if value_max is not None:
value = min(value, value_max)
eps = 1e-6
old_value = getattr(obj, pname)
if isinstance(value, list):
for i, v in enumerate(value):
if v != old_value[i]:
setattr(obj, pname, value)
break
elif abs(value - old_value) > eps:
setattr(obj, pname, value)
def __set_body_force_property(fluidsim, body_force):
eps = 1e-6
old_body_force = fluidsim.get_constant_body_force()
new_body_force = Vector3(body_force[0], body_force[1], body_force[2])
if (new_body_force - old_body_force).length() > eps:
fluidsim.reset_body_force()
fluidsim.add_body_force(body_force)
def __set_whitewater_emission_boundary_property(fluidsim, bounds):
eps = 1e-6
old_bounds = fluidsim.diffuse_emitter_generation_bounds
if ((bounds.position - old_bounds.position).length() > eps or
abs(bounds.width - old_bounds.width) > eps or
abs(bounds.height - old_bounds.height) > eps or
abs(bounds.depth - old_bounds.depth) > eps):
fluidsim.diffuse_emitter_generation_bounds = bounds
def __set_meshing_volume_object(fluidsim, data, frameid=0):
init_data = data.domain_data.initialize
surface_data = data.domain_data.surface
bbox = init_data.bbox
isize, jsize, ksize = init_data.isize, init_data.jsize, init_data.ksize
dx = init_data.dx
meshing_volume_mode = __get_parameter_data(surface_data.meshing_volume_mode, frameid)
if meshing_volume_mode != 'MESHING_VOLUME_MODE_OBJECT':
return
if not surface_data.meshing_volume_object:
return
object_name = surface_data.meshing_volume_object
if __is_object_dynamic(object_name):
timeline_frame = __get_timeline_frame()
previous_mesh, current_mesh, next_mesh = __extract_dynamic_frame_meshes(object_name, timeline_frame)
volume_object = MeshObject(isize, jsize, ksize, dx)
volume_object.update_mesh_animated(previous_mesh, current_mesh, next_mesh)
else:
mesh = __extract_static_frame_mesh(object_name)
volume_object = MeshObject(isize, jsize, ksize, dx)
volume_object.update_mesh_static(mesh)
fluidsim.set_meshing_volume(volume_object)
surface_data.meshing_volume_object_class = volume_object
def __update_animatable_domain_properties(fluidsim, data, frameno):
dprops = data.domain_data
# Simulation Settings
fluid_boundary_collisions = __get_parameter_data(dprops.simulation.fluid_boundary_collisions, frameno)
__set_property(fluidsim, 'fluid_boundary_collisions', fluid_boundary_collisions)
open_boundary_width = __get_parameter_data(dprops.simulation.fluid_open_boundary_width, frameno)
__set_property(fluidsim, 'fluid_open_boundary_width', open_boundary_width)
# Whitewater Simulation Settings
whitewater = dprops.whitewater
if __get_parameter_data(whitewater.enable_whitewater_simulation):
is_generating_whitewater = __get_parameter_data(whitewater.enable_whitewater_emission, frameno)
__set_property(fluidsim, 'enable_diffuse_particle_emission', is_generating_whitewater)
is_foam_enabled = __get_parameter_data(whitewater.enable_foam, frameno)
is_bubbles_enabled = __get_parameter_data(whitewater.enable_bubbles, frameno)
is_spray_enabled = __get_parameter_data(whitewater.enable_spray, frameno)
is_dust_enabled = __get_parameter_data(whitewater.enable_dust, frameno)
is_dust_boundary_emission_enabled = __get_parameter_data(whitewater.enable_dust_emission_near_boundary, frameno)
__set_property(fluidsim, 'enable_diffuse_foam', is_foam_enabled)
__set_property(fluidsim, 'enable_diffuse_bubbles', is_bubbles_enabled)
__set_property(fluidsim, 'enable_diffuse_spray', is_spray_enabled)
__set_property(fluidsim, 'enable_diffuse_dust', is_dust_enabled)
__set_property(fluidsim, 'enable_boundary_diffuse_dust_emission', is_dust_boundary_emission_enabled)
whitewater_motion_blur = __get_parameter_data(whitewater.generate_whitewater_motion_blur_data, frameno)
__set_property(fluidsim, 'enable_whitewater_motion_blur', whitewater_motion_blur)
emitter_pct = __get_parameter_data(whitewater.whitewater_emitter_generation_rate, frameno)
__set_property(fluidsim, 'diffuse_emitter_generation_rate', emitter_pct / 100)
wavecrest_rate = __get_parameter_data(whitewater.wavecrest_emission_rate, frameno)
turbulence_rate = __get_parameter_data(whitewater.turbulence_emission_rate, frameno)
dust_rate = __get_parameter_data(whitewater.dust_emission_rate, frameno)
__set_property(fluidsim, 'diffuse_particle_wavecrest_emission_rate', wavecrest_rate)
__set_property(fluidsim, 'diffuse_particle_turbulence_emission_rate', turbulence_rate)
__set_property(fluidsim, 'diffuse_particle_dust_emission_rate', dust_rate)
spray_emission_speed = __get_parameter_data(whitewater.spray_emission_speed, frameno)
__set_property(fluidsim, 'diffuse_spray_emission_speed', spray_emission_speed)
min_speed, max_speed = __get_parameter_data(whitewater.min_max_whitewater_energy_speed, frameno)
__set_property(fluidsim, 'min_diffuse_emitter_energy', 0.5 * min_speed * min_speed)
__set_property(fluidsim, 'max_diffuse_emitter_energy', 0.5 * max_speed * max_speed)
mink, maxk = __get_parameter_data(whitewater.min_max_whitewater_wavecrest_curvature, frameno)
__set_property(fluidsim, 'min_diffuse_wavecrest_curvature', mink)
__set_property(fluidsim, 'max_diffuse_wavecrest_curvature', maxk)
mint, maxt = __get_parameter_data(whitewater.min_max_whitewater_turbulence, frameno)
__set_property(fluidsim, 'min_diffuse_turbulence', mint)
__set_property(fluidsim, 'max_diffuse_turbulence', maxt)
max_particles = __get_parameter_data(whitewater.max_whitewater_particles, frameno)
__set_property(fluidsim, 'max_num_diffuse_particles', int(max_particles * 1e6))
bounds = __get_emission_boundary(whitewater, fluidsim)
__set_whitewater_emission_boundary_property(fluidsim, bounds)
min_lifespan, max_lifespan = __get_parameter_data(whitewater.min_max_whitewater_lifespan, frameno)
lifespan_variance = __get_parameter_data(whitewater.whitewater_lifespan_variance, frameno)
__set_property(fluidsim, 'min_diffuse_particle_lifetime', min_lifespan)
__set_property(fluidsim, 'max_diffuse_particle_lifetime', max_lifespan)
__set_property(fluidsim, 'diffuse_particle_lifetime_variance', lifespan_variance)
foam_modifier = __get_parameter_data(whitewater.foam_lifespan_modifier, frameno)
bubble_modifier = __get_parameter_data(whitewater.bubble_lifespan_modifier, frameno)
spray_modifier = __get_parameter_data(whitewater.spray_lifespan_modifier, frameno)
dust_modifier = __get_parameter_data(whitewater.dust_lifespan_modifier, frameno)
__set_property(fluidsim, 'foam_particle_lifetime_modifier', 1.0 / max(foam_modifier, 1e-6))
__set_property(fluidsim, 'bubble_particle_lifetime_modifier', 1.0 / max(bubble_modifier, 1e-6))
__set_property(fluidsim, 'spray_particle_lifetime_modifier', 1.0 / max(spray_modifier, 1e-6))
__set_property(fluidsim, 'dust_particle_lifetime_modifier', 1.0 / max(dust_modifier, 1e-6))
boundary_collisions_mode = __get_parameter_data(whitewater.whitewater_boundary_collisions_mode, frameno)
if boundary_collisions_mode == 'BOUNDARY_COLLISIONS_MODE_INHERIT':
fluid_boundary_collisions = __get_parameter_data(dprops.simulation.fluid_boundary_collisions, frameno)
foam_boundary_collisions = fluid_boundary_collisions
bubble_boundary_collisions = fluid_boundary_collisions
spray_boundary_collisions = fluid_boundary_collisions
dust_boundary_collisions = fluid_boundary_collisions
else:
foam_boundary_collisions = __get_parameter_data(whitewater.foam_boundary_collisions, frameno)
bubble_boundary_collisions = __get_parameter_data(whitewater.bubble_boundary_collisions, frameno)
spray_boundary_collisions = __get_parameter_data(whitewater.spray_boundary_collisions, frameno)
dust_boundary_collisions = __get_parameter_data(whitewater.dust_boundary_collisions, frameno)
__set_property(fluidsim, 'foam_boundary_collisions', foam_boundary_collisions)
__set_property(fluidsim, 'bubble_boundary_collisions', bubble_boundary_collisions)
__set_property(fluidsim, 'spray_boundary_collisions', spray_boundary_collisions)
__set_property(fluidsim, 'dust_boundary_collisions', dust_boundary_collisions)
"""
foam_behaviour = __get_parameter_data(whitewater.foam_boundary_behaviour, frameno)
bubble_behaviour = __get_parameter_data(whitewater.bubble_boundary_behaviour, frameno)
spray_behaviour = __get_parameter_data(whitewater.spray_boundary_behaviour, frameno)
dust_behaviour = __get_parameter_data(whitewater.bubble_boundary_behaviour, frameno) # Same as bubble for now
foam_behaviour = __get_limit_behaviour_enum(foam_behaviour)
bubble_behaviour = __get_limit_behaviour_enum(bubble_behaviour)
spray_behaviour = __get_limit_behaviour_enum(spray_behaviour)
dust_behaviour = __get_limit_behaviour_enum(dust_behaviour)
__set_property(fluidsim, 'diffuse_foam_limit_behaviour', foam_behaviour)
__set_property(fluidsim, 'diffuse_bubble_limit_behaviour', bubble_behaviour)
__set_property(fluidsim, 'diffuse_spray_limit_behaviour', spray_behaviour)
__set_property(fluidsim, 'diffuse_dust_limit_behaviour', dust_behaviour)
foam_active_sides = __get_parameter_data(whitewater.foam_boundary_active, frameno)
bubble_active_sides = __get_parameter_data(whitewater.bubble_boundary_active, frameno)
spray_active_sides = __get_parameter_data(whitewater.spray_boundary_active, frameno)
dust_active_sides = __get_parameter_data(whitewater.bubble_boundary_active, frameno) # Same as bubble for now
__set_property(fluidsim, 'diffuse_foam_active_boundary_sides', foam_active_sides)
__set_property(fluidsim, 'diffuse_bubble_active_boundary_sides', bubble_active_sides)
__set_property(fluidsim, 'diffuse_spray_active_boundary_sides', spray_active_sides)
__set_property(fluidsim, 'diffuse_dust_active_boundary_sides', dust_active_sides)
"""
strength = __get_parameter_data(whitewater.foam_advection_strength, frameno)
foam_depth = __get_parameter_data(whitewater.foam_layer_depth, frameno)
foam_offset = __get_parameter_data(whitewater.foam_layer_offset, frameno)
__set_property(fluidsim, 'diffuse_foam_layer_depth', foam_depth)
__set_property(fluidsim, 'diffuse_foam_layer_offset', foam_offset)
__set_property(fluidsim, 'diffuse_foam_advection_strength', strength)
preserve_foam = __get_parameter_data(whitewater.preserve_foam, frameno)
preserve_rate = __get_parameter_data(whitewater.foam_preservation_rate, frameno)
min_density, max_density = __get_parameter_data(whitewater.min_max_foam_density, frameno)
__set_property(fluidsim, 'enable_diffuse_preserve_foam', preserve_foam)
__set_property(fluidsim, 'diffuse_foam_preservation_rate', preserve_rate)
__set_property(fluidsim, 'min_diffuse_foam_density', min_density)
__set_property(fluidsim, 'max_diffuse_foam_density', max_density)
drag = __get_parameter_data(whitewater.bubble_drag_coefficient, frameno)
bouyancy = __get_parameter_data(whitewater.bubble_bouyancy_coefficient, frameno)
__set_property(fluidsim, 'diffuse_bubble_drag_coefficient', drag)
__set_property(fluidsim, 'diffuse_bubble_bouyancy_coefficient', bouyancy)
drag = __get_parameter_data(whitewater.dust_drag_coefficient, frameno)
bouyancy = __get_parameter_data(whitewater.dust_bouyancy_coefficient, frameno)
__set_property(fluidsim, 'diffuse_dust_drag_coefficient', drag)
__set_property(fluidsim, 'diffuse_dust_bouyancy_coefficient', bouyancy)
drag = __get_parameter_data(whitewater.spray_drag_coefficient, frameno)
__set_property(fluidsim, 'diffuse_spray_drag_coefficient', drag)
base_level = __get_parameter_data(whitewater.obstacle_influence_base_level, frameno)
__set_property(fluidsim, 'diffuse_obstacle_influence_base_level', base_level)
decay_rate = __get_parameter_data(whitewater.obstacle_influence_decay_rate, frameno)
__set_property(fluidsim, 'diffuse_obstacle_influence_decay_rate', decay_rate)
# World Settings
world = dprops.world
gravity = __get_parameter_data(world.gravity, frameno)
if __get_parameter_data(world.gravity_type, frameno) == 'GRAVITY_TYPE_SCENE':
use_gravity = bool(__get_parameter_data(world.scene_use_gravity, frameno))
if not use_gravity:
gravity = [0.0, 0.0, 0.0]
__set_body_force_property(fluidsim, gravity)
weight_fluid_particles = __get_parameter_data(world.force_field_weight_fluid_particles, frameno)
weight_whitewater_foam = __get_parameter_data(world.force_field_weight_whitewater_foam, frameno)
weight_whitewater_bubble = __get_parameter_data(world.force_field_weight_whitewater_bubble, frameno)
weight_whitewater_spray = __get_parameter_data(world.force_field_weight_whitewater_spray, frameno)
weight_whitewater_dust = __get_parameter_data(world.force_field_weight_whitewater_dust, frameno)
__set_property(fluidsim, 'force_field_weight_fluid_particles', weight_fluid_particles)
__set_property(fluidsim, 'force_field_weight_whitewater_foam', weight_whitewater_foam)
__set_property(fluidsim, 'force_field_weight_whitewater_bubble', weight_whitewater_bubble)
__set_property(fluidsim, 'force_field_weight_whitewater_spray', weight_whitewater_spray)
__set_property(fluidsim, 'force_field_weight_whitewater_dust', weight_whitewater_dust)
is_viscosity_enabled = __get_parameter_data(world.enable_viscosity, frameno)
if is_viscosity_enabled:
surface = dprops.surface
is_variable_viscosity_enabled = __get_parameter_data(surface.enable_viscosity_attribute, frameno)
if is_variable_viscosity_enabled:
__set_property(fluidsim, 'viscosity', 0.0)
else:
constant_viscosity = __get_viscosity_value(world, frameno)
__set_property(fluidsim, 'viscosity', constant_viscosity)
tolerance_int = __get_parameter_data(world.viscosity_solver_error_tolerance, frameno)
error_tolerance = 1.0 * 10.0**(-tolerance_int)
__set_property(fluidsim, 'viscosity_solver_error_tolerance', error_tolerance)
elif fluidsim.viscosity > 0.0:
__set_property(fluidsim, 'viscosity', 0.0)
is_surface_tension_enabled = __get_parameter_data(world.enable_surface_tension, frameno)
if is_surface_tension_enabled:
surface_tension = __get_surface_tension_value(world, frameno)
__set_property(fluidsim, 'surface_tension', surface_tension)
mincfl, maxcfl = world.minimum_surface_tension_cfl, world.maximum_surface_tension_cfl
accuracy_pct = __get_parameter_data(world.surface_tension_accuracy, frameno) / 100.0
surface_tension_number = mincfl + (1.0 - accuracy_pct) * (maxcfl - mincfl)
__set_property(fluidsim, 'surface_tension_condition_number', surface_tension_number)
elif fluidsim.surface_tension > 0.0:
__set_property(fluidsim, 'surface_tension', 0.0)
is_sheet_seeding_enabled = __get_parameter_data(world.enable_sheet_seeding, frameno)
__set_property(fluidsim, 'enable_sheet_seeding', is_sheet_seeding_enabled)
if is_sheet_seeding_enabled:
sheet_fill_rate = __get_parameter_data(world.sheet_fill_rate, frameno)
threshold = __get_parameter_data(world.sheet_fill_threshold, frameno)
__set_property(fluidsim, 'sheet_fill_rate', sheet_fill_rate, value_min=0, value_max=1.0)
__set_property(fluidsim, 'sheet_fill_threshold', threshold - 1, value_min=-1.0, value_max=0.0)
friction = __get_parameter_data(world.boundary_friction, frameno)
__set_property(fluidsim, 'boundary_friction', friction, value_min=0.0, value_max=1.0)
# Fluid Particle Settings
particles = dprops.particles
output_amount = __get_parameter_data(particles.fluid_particle_output_amount, frameno)
__set_property(fluidsim, 'fluid_particle_output_amount', output_amount, value_min=0.0, value_max=1.0)
enable_fluid_particle_surface_output = __get_parameter_data(particles.enable_fluid_particle_surface_output, frameno)
__set_property(fluidsim, 'enable_fluid_particle_surface_output', enable_fluid_particle_surface_output)
enable_fluid_particle_boundary_output = __get_parameter_data(particles.enable_fluid_particle_boundary_output, frameno)
__set_property(fluidsim, 'enable_fluid_particle_boundary_output', enable_fluid_particle_boundary_output)
enable_fluid_particle_interior_output = __get_parameter_data(particles.enable_fluid_particle_interior_output, frameno)
__set_property(fluidsim, 'enable_fluid_particle_interior_output', enable_fluid_particle_interior_output)
source_id = __get_parameter_data(particles.fluid_particle_source_id_blacklist, frameno)
__set_property(fluidsim, 'fluid_particle_source_id_blacklist', source_id)
# Surface Settings
surface = dprops.surface
enable_surface_mesh_generation = __get_parameter_data(surface.enable_surface_mesh_generation, frameno)
__set_property(fluidsim, 'enable_surface_reconstruction', enable_surface_mesh_generation)
subdivisions = __get_parameter_data(surface.subdivisions, frameno) + 1
__set_property(fluidsim, 'surface_subdivision_level', subdivisions)
compute_chunk_mode = __get_parameter_data(surface.compute_chunk_mode, frameno)
if compute_chunk_mode == 'COMPUTE_CHUNK_MODE_AUTO':
num_chunks = __get_parameter_data(surface.compute_chunks_auto, frameno)
elif compute_chunk_mode == 'COMPUTE_CHUNK_MODE_FIXED':
num_chunks = __get_parameter_data(surface.compute_chunks_fixed, frameno)
__set_property(fluidsim, 'num_polygonizer_slices', num_chunks)
particle_scale = __get_parameter_data(surface.particle_scale, frameno)
particle_scale *= surface.native_particle_scale
__set_property(fluidsim, 'marker_particle_scale', particle_scale)
smoothing_value = __get_parameter_data(surface.smoothing_value, frameno)
smoothing_iterations = __get_parameter_data(surface.smoothing_iterations, frameno)
__set_property(fluidsim, 'surface_smoothing_value', smoothing_value)
__set_property(fluidsim, 'surface_smoothing_iterations', smoothing_iterations)
enable_meshing_offset = __get_parameter_data(surface.enable_meshing_offset, frameno)
__set_property(fluidsim, 'enable_obstacle_meshing_offset', enable_meshing_offset)
meshing_mode = __get_parameter_data(surface.obstacle_meshing_mode, frameno)
meshing_offset = __get_obstacle_meshing_offset(meshing_mode)
__set_property(fluidsim, 'obstacle_meshing_offset', meshing_offset)
remove_near_domain = __get_parameter_data(surface.remove_mesh_near_domain, frameno)
near_domain_distance = __get_parameter_data(surface.remove_mesh_near_domain_distance, frameno) - 1
__set_property(fluidsim, 'enable_remove_surface_near_domain', remove_near_domain)
__set_property(fluidsim, 'remove_surface_near_domain_distance', near_domain_distance)
domain_sides = __get_parameter_data(surface.remove_mesh_near_domain_sides, frameno)
__set_property(fluidsim, 'remove_surface_near_domain_sides', domain_sides)
invert_contact = __get_parameter_data(surface.invert_contact_normals, frameno)
__set_property(fluidsim, 'enable_inverted_contact_normals', invert_contact)
motion_blur = __get_parameter_data(surface.generate_motion_blur_data, frameno)
__set_property(fluidsim, 'enable_surface_motion_blur', motion_blur)
age_radius = __get_parameter_data(surface.age_attribute_radius, frameno)
__set_property(fluidsim, 'surface_age_attribute_radius', age_radius)
lifetime_radius = __get_parameter_data(surface.lifetime_attribute_radius, frameno)
__set_property(fluidsim, 'surface_lifetime_attribute_radius', lifetime_radius)
base_death_time = __get_parameter_data(surface.lifetime_attribute_death_time, frameno)
__set_property(fluidsim, 'surface_lifetime_attribute_death_time', base_death_time)
whitewater_proximity_radius = __get_parameter_data(surface.whitewater_proximity_attribute_radius, frameno)
__set_property(fluidsim, 'surface_whitewater_proximity_attribute_radius', whitewater_proximity_radius)
color_radius = __get_parameter_data(surface.color_attribute_radius, frameno)
__set_property(fluidsim, 'surface_color_attribute_radius', color_radius)
enable_mixing = __get_parameter_data(surface.enable_color_attribute_mixing, frameno)
__set_property(fluidsim, 'enable_surface_color_attribute_mixing', enable_mixing)
mixing_rate = __get_parameter_data(surface.color_attribute_mixing_rate, frameno)
__set_property(fluidsim, 'surface_color_attribute_mixing_rate', mixing_rate)
mixing_radius = __get_parameter_data(surface.color_attribute_mixing_radius, frameno)
__set_property(fluidsim, 'surface_color_attribute_mixing_radius', mixing_radius)
# Advanced Settings
advanced = dprops.advanced
min_substeps, max_substeps = __get_parameter_data(advanced.min_max_time_steps_per_frame, frameno)
__set_property(fluidsim, 'min_time_steps_per_frame', min_substeps)
__set_property(fluidsim, 'max_time_steps_per_frame', max_substeps)
enable_obstacle_time_stepping = \
__get_parameter_data(advanced.enable_adaptive_obstacle_time_stepping, frameno)
__set_property(fluidsim, 'enable_adaptive_obstacle_time_stepping', enable_obstacle_time_stepping)
enable_force_field_time_stepping = \
__get_parameter_data(advanced.enable_adaptive_force_field_time_stepping, frameno)
__set_property(fluidsim, 'enable_adaptive_force_field_time_stepping', enable_force_field_time_stepping)
jitter_factor = __get_parameter_data(advanced.particle_jitter_factor, frameno)
__set_property(fluidsim, 'marker_particle_jitter_factor', jitter_factor)
jitter_surface = __get_parameter_data(advanced.jitter_surface_particles, frameno)
__set_property(fluidsim, 'jitter_surface_marker_particles', jitter_surface)
pressure_solver_iterations = __get_parameter_data(advanced.pressure_solver_max_iterations, frameno)
__set_property(fluidsim, 'pressure_solver_max_iterations', pressure_solver_iterations)
viscosity_solver_iterations = __get_parameter_data(advanced.viscosity_solver_max_iterations, frameno)
__set_property(fluidsim, 'viscosity_solver_max_iterations', viscosity_solver_iterations)
PICFLIP_ratio = __get_parameter_data(advanced.PICFLIP_ratio, frameno)
__set_property(fluidsim, 'PICFLIP_ratio', PICFLIP_ratio)
PICAPIC_ratio = __get_parameter_data(advanced.PICAPIC_ratio, frameno)
__set_property(fluidsim, 'PICAPIC_ratio', PICAPIC_ratio)
CFL_number = __get_parameter_data(advanced.CFL_condition_number, frameno)
__set_property(fluidsim, 'CFL_condition_number', CFL_number)
enable_velocity_removal = __get_parameter_data(advanced.enable_extreme_velocity_removal, frameno)
__set_property(fluidsim, 'enable_extreme_velocity_removal', enable_velocity_removal)
threading_mode = __get_parameter_data(advanced.threading_mode, frameno)
if threading_mode == 'THREADING_MODE_AUTO_DETECT':
num_threads = __get_parameter_data(advanced.num_threads_auto_detect, frameno)
elif threading_mode == 'THREADING_MODE_FIXED':
num_threads = __get_parameter_data(advanced.num_threads_fixed, frameno)
__set_property(fluidsim, 'max_thread_count', num_threads)
enable_async_meshing = __get_parameter_data(advanced.enable_asynchronous_meshing, frameno)
__set_property(fluidsim, 'enable_asynchronous_meshing', enable_async_meshing)
enable_fracture_optimization = __get_parameter_data(advanced.enable_fracture_optimization, frameno)
__set_property(fluidsim, 'enable_fracture_optimization', enable_fracture_optimization)
precomp_static_sdf = __get_parameter_data(advanced.precompute_static_obstacles, frameno)
__set_property(fluidsim, 'enable_static_solid_levelset_precomputation', precomp_static_sdf)
reserve_temp_grids = __get_parameter_data(advanced.reserve_temporary_grids, frameno)
__set_property(fluidsim, 'enable_temporary_mesh_levelset', reserve_temp_grids)
# Debug Settings
debug = dprops.debug
export_internal_obstacle_mesh = __get_parameter_data(debug.export_internal_obstacle_mesh, frameno)
__set_property(fluidsim, 'enable_internal_obstacle_mesh_output', export_internal_obstacle_mesh)
# Caches created in older versions may not contain force field data. Ignore these features
# if force field data cannot be found in the cache
is_force_field_data_available = data.force_field_data is not None
if is_force_field_data_available:
export_force_field = __get_parameter_data(debug.export_force_field, frameno)
__set_property(fluidsim, 'enable_force_field_debug_output', export_force_field)
def __update_animatable_properties(fluidsim, data, frameno):
geometry_database = __get_geometry_database()
simulation_data = __get_simulation_data()
timeline_frame = __get_timeline_frame()
geometry_data = geometry_database.get_mesh_geometry_data_dict_for_frame(simulation_data, timeline_frame)
__update_animatable_inflow_properties(data, geometry_data, frameno)
__update_animatable_outflow_properties(data, geometry_data, frameno)
__update_animatable_force_field_properties(data, frameno)
__update_animatable_obstacle_properties(data, geometry_data, frameno)
__update_animatable_meshing_volume_properties(data, frameno)
__update_animatable_domain_properties(fluidsim, data, frameno)
def __frame_number_to_string(frameno):
return str(frameno).zfill(6)
def __write_bounds_data(cache_directory, fluidsim, frameno):
offset = fluidsim.get_domain_offset()
scale = fluidsim.get_domain_scale()
dims = fluidsim.get_simulation_dimensions()
grid_dims = fluidsim.get_grid_dimensions()
dx = fluidsim.get_cell_size()
bounds = {
"x": offset.x, "y": offset.y, "z": offset.z,
"width": dims.x * scale,
"height": dims.y * scale,
"depth": dims.z * scale,
"dx": dx * scale,
"isize": grid_dims.i,
"jsize": grid_dims.j,
"ksize": grid_dims.k
}
fstring = __frame_number_to_string(frameno)
bounds_filename = "bounds" + fstring + ".bbox"
bounds_filepath = os.path.join(cache_directory, "bakefiles", bounds_filename)
bounds_json = json.dumps(bounds)
with open(bounds_filepath, 'w', encoding='utf-8') as f:
f.write(bounds_json)
def __write_surface_data(cache_directory, fluidsim, frameno):
fstring = __frame_number_to_string(frameno)
surface_filename = fstring + ".bobj"
surface_filepath = os.path.join(cache_directory, "bakefiles", surface_filename)
filedata = fluidsim.get_surface_data()
with open(surface_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_surface_motion_blur:
blur_filename = "blur" + fstring + ".bobj"
blur_filepath = os.path.join(cache_directory, "bakefiles", blur_filename)
filedata = fluidsim.get_surface_blur_data()
with open(blur_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_surface_velocity_attribute:
velocity_filename = "velocity" + fstring + ".bobj"
velocity_filepath = os.path.join(cache_directory, "bakefiles", velocity_filename)
filedata = fluidsim.get_surface_velocity_attribute_data()
with open(velocity_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_surface_vorticity_attribute:
vorticity_filename = "vorticity" + fstring + ".bobj"
vorticity_filepath = os.path.join(cache_directory, "bakefiles", vorticity_filename)
filedata = fluidsim.get_surface_vorticity_attribute_data()
with open(vorticity_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_surface_speed_attribute:
speed_filename = "speed" + fstring + ".data"
speed_filepath = os.path.join(cache_directory, "bakefiles", speed_filename)
filedata = fluidsim.get_surface_speed_attribute_data()
with open(speed_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_surface_age_attribute:
age_filename = "age" + fstring + ".data"
age_filepath = os.path.join(cache_directory, "bakefiles", age_filename)
filedata = fluidsim.get_surface_age_attribute_data()
with open(age_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_surface_lifetime_attribute:
lifetime_filename = "lifetime" + fstring + ".data"
lifetime_filepath = os.path.join(cache_directory, "bakefiles", lifetime_filename)
filedata = fluidsim.get_surface_lifetime_attribute_data()
with open(lifetime_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_surface_whitewater_proximity_attribute:
whitewater_proximity_filename = "whitewaterproximity" + fstring + ".bobj"
whitewater_proximity_filepath = os.path.join(cache_directory, "bakefiles", whitewater_proximity_filename)
filedata = fluidsim.get_surface_whitewater_proximity_attribute_data()
with open(whitewater_proximity_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_surface_color_attribute:
color_filename = "color" + fstring + ".bobj"
color_filepath = os.path.join(cache_directory, "bakefiles", color_filename)
filedata = fluidsim.get_surface_color_attribute_data()
with open(color_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_surface_source_id_attribute:
source_id_filename = "sourceid" + fstring + ".data"
source_id_filepath = os.path.join(cache_directory, "bakefiles", source_id_filename)
filedata = fluidsim.get_surface_source_id_attribute_data()
with open(source_id_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_surface_viscosity_attribute:
viscosity_filename = "viscosity" + fstring + ".data"
viscosity_filepath = os.path.join(cache_directory, "bakefiles", viscosity_filename)
filedata = fluidsim.get_surface_viscosity_attribute_data()
with open(viscosity_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_surface_density_attribute:
density_filename = "density" + fstring + ".data"
density_filepath = os.path.join(cache_directory, "bakefiles", density_filename)
filedata = fluidsim.get_surface_density_attribute_data()
with open(density_filepath, 'wb') as f:
f.write(filedata)
preview_filename = "preview" + fstring + ".bobj"
preview_filepath = os.path.join(cache_directory, "bakefiles", preview_filename)
filedata = fluidsim.get_surface_preview_data()
with open(preview_filepath, 'wb') as f:
f.write(filedata)
def __write_whitewater_data(cache_directory, fluidsim, frameno):
fstring = __frame_number_to_string(frameno)
foam_filename = "foam" + fstring + ".wwp"
foam_filepath = os.path.join(cache_directory, "bakefiles", foam_filename)
filedata = fluidsim.get_diffuse_foam_data()
with open(foam_filepath, 'wb') as f:
f.write(filedata)
bubble_filename = "bubble" + fstring + ".wwp"
bubble_filepath = os.path.join(cache_directory, "bakefiles", bubble_filename)
filedata = fluidsim.get_diffuse_bubble_data()
with open(bubble_filepath, 'wb') as f:
f.write(filedata)
spray_filename = "spray" + fstring + ".wwp"
spray_filepath = os.path.join(cache_directory, "bakefiles", spray_filename)
filedata = fluidsim.get_diffuse_spray_data()
with open(spray_filepath, 'wb') as f:
f.write(filedata)
dust_filename = "dust" + fstring + ".wwp"
dust_filepath = os.path.join(cache_directory, "bakefiles", dust_filename)
filedata = fluidsim.get_diffuse_dust_data()
with open(dust_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_whitewater_motion_blur:
foam_blur_filename = "blurfoam" + fstring + ".wwp"
foam_blur_filepath = os.path.join(cache_directory, "bakefiles", foam_blur_filename)
filedata = fluidsim.get_diffuse_foam_blur_data()
with open(foam_blur_filepath, 'wb') as f:
f.write(filedata)
bubble_blur_filename = "blurbubble" + fstring + ".wwp"
bubble_blur_filepath = os.path.join(cache_directory, "bakefiles", bubble_blur_filename)
filedata = fluidsim.get_diffuse_bubble_blur_data()
with open(bubble_blur_filepath, 'wb') as f:
f.write(filedata)
spray_blur_filename = "blurspray" + fstring + ".wwp"
spray_blur_filepath = os.path.join(cache_directory, "bakefiles", spray_blur_filename)
filedata = fluidsim.get_diffuse_spray_blur_data()
with open(spray_blur_filepath, 'wb') as f:
f.write(filedata)
dust_blur_filename = "blurdust" + fstring + ".wwp"
dust_blur_filepath = os.path.join(cache_directory, "bakefiles", dust_blur_filename)
filedata = fluidsim.get_diffuse_dust_blur_data()
with open(dust_blur_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_whitewater_velocity_attribute:
foam_velocity_filename = "velocityfoam" + fstring + ".wwp"
foam_velocity_filepath = os.path.join(cache_directory, "bakefiles", foam_velocity_filename)
filedata = fluidsim.get_whitewater_foam_velocity_attribute_data()
with open(foam_velocity_filepath, 'wb') as f:
f.write(filedata)
bubble_velocity_filename = "velocitybubble" + fstring + ".wwp"
bubble_velocity_filepath = os.path.join(cache_directory, "bakefiles", bubble_velocity_filename)
filedata = fluidsim.get_whitewater_bubble_velocity_attribute_data()
with open(bubble_velocity_filepath, 'wb') as f:
f.write(filedata)
spray_velocity_filename = "velocityspray" + fstring + ".wwp"
spray_velocity_filepath = os.path.join(cache_directory, "bakefiles", spray_velocity_filename)
filedata = fluidsim.get_whitewater_spray_velocity_attribute_data()
with open(spray_velocity_filepath, 'wb') as f:
f.write(filedata)
dust_velocity_filename = "velocitydust" + fstring + ".wwp"
dust_velocity_filepath = os.path.join(cache_directory, "bakefiles", dust_velocity_filename)
filedata = fluidsim.get_whitewater_dust_velocity_attribute_data()
with open(dust_velocity_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_whitewater_id_attribute:
foam_id_filename = "idfoam" + fstring + ".wwi"
foam_id_filepath = os.path.join(cache_directory, "bakefiles", foam_id_filename)
filedata = fluidsim.get_whitewater_foam_id_attribute_data()
with open(foam_id_filepath, 'wb') as f:
f.write(filedata)
bubble_id_filename = "idbubble" + fstring + ".wwi"
bubble_id_filepath = os.path.join(cache_directory, "bakefiles", bubble_id_filename)
filedata = fluidsim.get_whitewater_bubble_id_attribute_data()
with open(bubble_id_filepath, 'wb') as f:
f.write(filedata)
spray_id_filename = "idspray" + fstring + ".wwi"
spray_id_filepath = os.path.join(cache_directory, "bakefiles", spray_id_filename)
filedata = fluidsim.get_whitewater_spray_id_attribute_data()
with open(spray_id_filepath, 'wb') as f:
f.write(filedata)
dust_id_filename = "iddust" + fstring + ".wwi"
dust_id_filepath = os.path.join(cache_directory, "bakefiles", dust_id_filename)
filedata = fluidsim.get_whitewater_dust_id_attribute_data()
with open(dust_id_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_whitewater_lifetime_attribute:
foam_lifetime_filename = "lifetimefoam" + fstring + ".wwf"
foam_lifetime_filepath = os.path.join(cache_directory, "bakefiles", foam_lifetime_filename)
filedata = fluidsim.get_whitewater_foam_lifetime_attribute_data()
with open(foam_lifetime_filepath, 'wb') as f:
f.write(filedata)
bubble_lifetime_filename = "lifetimebubble" + fstring + ".wwf"
bubble_lifetime_filepath = os.path.join(cache_directory, "bakefiles", bubble_lifetime_filename)
filedata = fluidsim.get_whitewater_bubble_lifetime_attribute_data()
with open(bubble_lifetime_filepath, 'wb') as f:
f.write(filedata)
spray_lifetime_filename = "lifetimespray" + fstring + ".wwf"
spray_lifetime_filepath = os.path.join(cache_directory, "bakefiles", spray_lifetime_filename)
filedata = fluidsim.get_whitewater_spray_lifetime_attribute_data()
with open(spray_lifetime_filepath, 'wb') as f:
f.write(filedata)
dust_lifetime_filename = "lifetimedust" + fstring + ".wwf"
dust_lifetime_filepath = os.path.join(cache_directory, "bakefiles", dust_lifetime_filename)
filedata = fluidsim.get_whitewater_dust_lifetime_attribute_data()
with open(dust_lifetime_filepath, 'wb') as f:
f.write(filedata)
def __write_fluid_particle_data(cache_directory, fluidsim, frameno):
fstring = __frame_number_to_string(frameno)
particle_filename = "fluidparticles" + fstring + ".ffp3"
particle_filepath = os.path.join(cache_directory, "bakefiles", particle_filename)
filedata = fluidsim.get_fluid_particle_data()
with open(particle_filepath, 'wb') as f:
f.write(filedata)
particle_id_filename = "fluidparticlesid" + fstring + ".ffp3"
particle_id_filepath = os.path.join(cache_directory, "bakefiles", particle_id_filename)
filedata = fluidsim.get_fluid_particle_id_attribute_data()
with open(particle_id_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_fluid_particle_velocity_attribute:
particle_velocity_filename = "fluidparticlesvelocity" + fstring + ".ffp3"
particle_velocity_filepath = os.path.join(cache_directory, "bakefiles", particle_velocity_filename)
filedata = fluidsim.get_fluid_particle_velocity_attribute_data()
with open(particle_velocity_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_fluid_particle_speed_attribute:
particle_speed_filename = "fluidparticlesspeed" + fstring + ".ffp3"
particle_speed_filepath = os.path.join(cache_directory, "bakefiles", particle_speed_filename)
filedata = fluidsim.get_fluid_particle_speed_attribute_data()
with open(particle_speed_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_fluid_particle_vorticity_attribute:
particle_vorticity_filename = "fluidparticlesvorticity" + fstring + ".ffp3"
particle_vorticity_filepath = os.path.join(cache_directory, "bakefiles", particle_vorticity_filename)
filedata = fluidsim.get_fluid_particle_vorticity_attribute_data()
with open(particle_vorticity_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_fluid_particle_color_attribute:
particle_color_filename = "fluidparticlescolor" + fstring + ".ffp3"
particle_color_filepath = os.path.join(cache_directory, "bakefiles", particle_color_filename)
filedata = fluidsim.get_fluid_particle_color_attribute_data()
with open(particle_color_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_fluid_particle_age_attribute:
particle_age_filename = "fluidparticlesage" + fstring + ".ffp3"
particle_age_filepath = os.path.join(cache_directory, "bakefiles", particle_age_filename)
filedata = fluidsim.get_fluid_particle_age_attribute_data()
with open(particle_age_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_fluid_particle_lifetime_attribute:
particle_lifetime_filename = "fluidparticleslifetime" + fstring + ".ffp3"
particle_lifetime_filepath = os.path.join(cache_directory, "bakefiles", particle_lifetime_filename)
filedata = fluidsim.get_fluid_particle_lifetime_attribute_data()
with open(particle_lifetime_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_surface_viscosity_attribute:
# Fluid particle viscosity attribute matches surface viscosity attribute
particle_viscosity_filename = "fluidparticlesviscosity" + fstring + ".ffp3"
particle_viscosity_filepath = os.path.join(cache_directory, "bakefiles", particle_viscosity_filename)
filedata = fluidsim.get_fluid_particle_viscosity_attribute_data()
with open(particle_viscosity_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_fluid_particle_density_attribute:
particle_density_filename = "fluidparticlesdensity" + fstring + ".ffp3"
particle_density_filepath = os.path.join(cache_directory, "bakefiles", particle_density_filename)
filedata = fluidsim.get_fluid_particle_density_attribute_data()
with open(particle_density_filepath, 'wb') as f:
f.write(filedata)
# flip_density_average attribute needs some more work
"""
particle_density_average_filename = "fluidparticlesdensityaverage" + fstring + ".ffp3"
particle_density_average_filepath = os.path.join(cache_directory, "bakefiles", particle_density_average_filename)
filedata = fluidsim.get_fluid_particle_density_average_attribute_data()
with open(particle_density_average_filepath, 'wb') as f:
f.write(filedata)
"""
if fluidsim.enable_fluid_particle_whitewater_proximity_attribute:
whitewater_proximity_filename = "fluidparticleswhitewaterproximity" + fstring + ".ffp3"
whitewater_proximity_filepath = os.path.join(cache_directory, "bakefiles", whitewater_proximity_filename)
filedata = fluidsim.get_fluid_particle_whitewater_proximity_attribute_data()
with open(whitewater_proximity_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_fluid_particle_source_id_attribute:
source_id_filename = "fluidparticlessourceid" + fstring + ".ffp3"
source_id_filepath = os.path.join(cache_directory, "bakefiles", source_id_filename)
filedata = fluidsim.get_fluid_particle_source_id_attribute_data()
with open(source_id_filepath, 'wb') as f:
f.write(filedata)
if fluidsim.enable_fluid_particle_uid_attribute:
uid_filename = "fluidparticlesuid" + fstring + ".ffp3"
uid_filepath = os.path.join(cache_directory, "bakefiles", uid_filename)
filedata = fluidsim.get_fluid_particle_uid_attribute_data()
with open(uid_filepath, 'wb') as f:
f.write(filedata)
uid_max_filename = "fluidparticlesuidmax" + fstring + ".txt"
uid_max_filepath = os.path.join(cache_directory, "bakefiles", uid_max_filename)
max_uid_value = fluidsim.get_current_fluid_particle_uid() - 1
with open(uid_max_filepath, 'w') as f:
f.write(str(max_uid_value))
def __write_fluid_particle_debug_data(cache_directory, fluidsim, frameno):
fstring = __frame_number_to_string(frameno)
particle_filename = "particles" + fstring + ".fpd"
particle_filepath = os.path.join(cache_directory, "bakefiles", particle_filename)
filedata = fluidsim.get_fluid_particle_debug_data()
with open(particle_filepath, 'wb') as f:
f.write(filedata)
def __write_internal_obstacle_mesh_data(cache_directory, fluidsim, frameno):
fstring = __frame_number_to_string(frameno)
obstacle_filename = "obstacle" + fstring + ".bobj"
obstacle_filepath = os.path.join(cache_directory, "bakefiles", obstacle_filename)
filedata = fluidsim.get_internal_obstacle_mesh_data()
with open(obstacle_filepath, 'wb') as f:
f.write(filedata)
def __write_force_field_debug_data(cache_directory, fluidsim, frameno):
fstring = __frame_number_to_string(frameno)
force_field_filename = "forcefield" + fstring + ".ffd"
force_field_filepath = os.path.join(cache_directory, "bakefiles", force_field_filename)
filedata = fluidsim.get_force_field_debug_data()
with open(force_field_filepath, 'wb') as f:
f.write(filedata)
def __write_logfile_data(cache_directory, logfile_name, fluidsim):
filedata = fluidsim.get_logfile_data()
logpath = os.path.join(cache_directory, "logs", logfile_name)
with open(logpath, 'a', encoding='utf-8') as f:
f.write(filedata)
def __get_mesh_stats_dict(mstats):
stats = {}
stats["enabled"] = bool(mstats.enabled)
stats["vertices"] = mstats.vertices
stats["triangles"] = mstats.triangles
stats["bytes"] = mstats.bytes
return stats
def __get_timing_stats_dict(tstats):
stats = {}
stats["total"] = tstats.total
stats["mesh"] = tstats.mesh
stats["advection"] = tstats.advection
stats["particles"] = tstats.particles
stats["pressure"] = tstats.pressure
stats["diffuse"] = tstats.diffuse
stats["viscosity"] = tstats.viscosity
stats["objects"] = tstats.objects
return stats
def __get_frame_stats_dict(cstats):
stats = {}
stats["frame"] = cstats.frame
stats["substeps"] = cstats.substeps
stats["delta_time"] = cstats.delta_time
stats["fluid_particles"] = cstats.fluid_particles
stats["diffuse_particles"] = cstats.diffuse_particles
stats["substeps"] = cstats.substeps
stats["performance_score"] = cstats.performance_score
stats["pressure_solver_enabled"] = cstats.pressure_solver_enabled
stats["pressure_solver_success"] = cstats.pressure_solver_success
stats["pressure_solver_error"] = cstats.pressure_solver_error
stats["pressure_solver_iterations"] = cstats.pressure_solver_iterations
stats["pressure_solver_max_iterations"] = cstats.pressure_solver_max_iterations
stats["viscosity_solver_enabled"] = cstats.viscosity_solver_enabled
stats["viscosity_solver_success"] = cstats.viscosity_solver_success
stats["viscosity_solver_error"] = cstats.viscosity_solver_error
stats["viscosity_solver_iterations"] = cstats.viscosity_solver_iterations
stats["viscosity_solver_max_iterations"] = cstats.viscosity_solver_max_iterations
stats["surface"] = __get_mesh_stats_dict(cstats.surface)
stats["preview"] = __get_mesh_stats_dict(cstats.preview)
stats["surfaceblur"] = __get_mesh_stats_dict(cstats.surfaceblur)
stats["surfacevelocity"] = __get_mesh_stats_dict(cstats.surfacevelocity)
stats["surfacespeed"] = __get_mesh_stats_dict(cstats.surfacespeed)
stats["surfacevorticity"] = __get_mesh_stats_dict(cstats.surfacevorticity)
stats["surfaceage"] = __get_mesh_stats_dict(cstats.surfaceage)
stats["surfacelifetime"] = __get_mesh_stats_dict(cstats.surfacelifetime)
stats["surfacewhitewaterproximity"] = __get_mesh_stats_dict(cstats.surfacewhitewaterproximity)
stats["surfacecolor"] = __get_mesh_stats_dict(cstats.surfacecolor)
stats["surfacesourceid"] = __get_mesh_stats_dict(cstats.surfacesourceid)
stats["surfaceviscosity"] = __get_mesh_stats_dict(cstats.surfaceviscosity)
stats["surfacedensity"] = __get_mesh_stats_dict(cstats.surfacedensity)
stats["foam"] = __get_mesh_stats_dict(cstats.foam)
stats["bubble"] = __get_mesh_stats_dict(cstats.bubble)
stats["spray"] = __get_mesh_stats_dict(cstats.spray)
stats["dust"] = __get_mesh_stats_dict(cstats.dust)
stats["foamblur"] = __get_mesh_stats_dict(cstats.foamblur)
stats["bubbleblur"] = __get_mesh_stats_dict(cstats.bubbleblur)
stats["sprayblur"] = __get_mesh_stats_dict(cstats.sprayblur)
stats["dustblur"] = __get_mesh_stats_dict(cstats.dustblur)
stats["foamvelocity"] = __get_mesh_stats_dict(cstats.foamvelocity)
stats["bubblevelocity"] = __get_mesh_stats_dict(cstats.bubblevelocity)
stats["sprayvelocity"] = __get_mesh_stats_dict(cstats.sprayvelocity)
stats["dustvelocity"] = __get_mesh_stats_dict(cstats.dustvelocity)
stats["foamid"] = __get_mesh_stats_dict(cstats.foamid)
stats["bubbleid"] = __get_mesh_stats_dict(cstats.bubbleid)
stats["sprayid"] = __get_mesh_stats_dict(cstats.sprayid)
stats["dustid"] = __get_mesh_stats_dict(cstats.dustid)
stats["foamlifetime"] = __get_mesh_stats_dict(cstats.foamlifetime)
stats["bubblelifetime"] = __get_mesh_stats_dict(cstats.bubblelifetime)
stats["spraylifetime"] = __get_mesh_stats_dict(cstats.spraylifetime)
stats["dustlifetime"] = __get_mesh_stats_dict(cstats.dustlifetime)
stats["fluidparticles"] = __get_mesh_stats_dict(cstats.fluidparticles)
stats["fluidparticlesid"] = __get_mesh_stats_dict(cstats.fluidparticlesid)
stats["fluidparticlesuid"] = __get_mesh_stats_dict(cstats.fluidparticlesuid)
stats["fluidparticlesvelocity"] = __get_mesh_stats_dict(cstats.fluidparticlesvelocity)
stats["fluidparticlesspeed"] = __get_mesh_stats_dict(cstats.fluidparticlesspeed)
stats["fluidparticlesvorticity"] = __get_mesh_stats_dict(cstats.fluidparticlesvorticity)
stats["fluidparticlescolor"] = __get_mesh_stats_dict(cstats.fluidparticlescolor)
stats["fluidparticlesage"] = __get_mesh_stats_dict(cstats.fluidparticlesage)
stats["fluidparticleslifetime"] = __get_mesh_stats_dict(cstats.fluidparticleslifetime)
stats["fluidparticlesviscosity"] = __get_mesh_stats_dict(cstats.fluidparticlesviscosity)
stats["fluidparticlesdensity"] = __get_mesh_stats_dict(cstats.fluidparticlesdensity)
# flip_density_average attribute needs some more work
#stats["fluidparticlesdensityaverage"] = __get_mesh_stats_dict(cstats.fluidparticlesdensityaverage)
stats["fluidparticleswhitewaterproximity"] = __get_mesh_stats_dict(cstats.fluidparticleswhitewaterproximity)
stats["fluidparticlessourceid"] = __get_mesh_stats_dict(cstats.fluidparticlessourceid)
stats["particles"] = __get_mesh_stats_dict(cstats.particles)
stats["obstacle"] = __get_mesh_stats_dict(cstats.obstacle)
stats["timing"] = __get_timing_stats_dict(cstats.timing)
return stats
def __write_frame_stats_data(cache_directory, fluidsim, frameno):
fstring = __frame_number_to_string(frameno)
filename = "framestats" + fstring + ".data"
tempdir = os.path.join(cache_directory, "temp")
statspath = os.path.join(tempdir, filename)
if not os.path.exists(tempdir):
os.makedirs(tempdir)
cstats = fluidsim.get_frame_stats_data()
stats = __get_frame_stats_dict(cstats)
filedata = json.dumps(stats, sort_keys=True, indent=4)
with open(statspath, 'w', encoding='utf-8') as f:
f.write(filedata)
def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno):
autosave_dir = os.path.join(cache_directory, "savestates", "autosave")
if not os.path.exists(autosave_dir):
os.makedirs(autosave_dir)
position_data_path = os.path.join(autosave_dir, "marker_particle_position.data")
velocity_data_path = os.path.join(autosave_dir, "marker_particle_velocity.data")
affinex_data_path = os.path.join(autosave_dir, "marker_particle_affinex.data")
affiney_data_path = os.path.join(autosave_dir, "marker_particle_affiney.data")
affinez_data_path = os.path.join(autosave_dir, "marker_particle_affinez.data")
age_data_path = os.path.join(autosave_dir, "marker_particle_age.data")
lifetime_data_path = os.path.join(autosave_dir, "marker_particle_lifetime.data")
color_data_path = os.path.join(autosave_dir, "marker_particle_color.data")
source_id_data_path = os.path.join(autosave_dir, "marker_particle_source_id.data")
uid_data_path = os.path.join(autosave_dir, "marker_particle_uid.data")
viscosity_data_path = os.path.join(autosave_dir, "marker_particle_viscosity.data")
density_data_path = os.path.join(autosave_dir, "marker_particle_density.data")
id_data_path = os.path.join(autosave_dir, "marker_particle_id.data")
diffuse_position_data_path = os.path.join(autosave_dir, "diffuse_particle_position.data")
diffuse_velocity_data_path = os.path.join(autosave_dir, "diffuse_particle_velocity.data")
diffuse_lifetime_data_path = os.path.join(autosave_dir, "diffuse_particle_lifetime.data")
diffuse_type_data_path = os.path.join(autosave_dir, "diffuse_particle_type.data")
diffuse_id_data_path = os.path.join(autosave_dir, "diffuse_particle_id.data")
autosave_info_path = os.path.join(autosave_dir, "autosave.state")
temp_extension = ".backup"
autosave_default_filepaths = [
position_data_path,
velocity_data_path,
autosave_info_path
]
autosave_apic_filepaths = [
affinex_data_path,
affiney_data_path,
affinez_data_path
]
autosave_age_filepaths = [
age_data_path
]
autosave_lifetime_filepaths = [
lifetime_data_path
]
autosave_color_filepaths = [
color_data_path
]
autosave_source_id_filepaths = [
source_id_data_path
]
autosave_uid_filepaths = [
uid_data_path
]
autosave_viscosity_filepaths = [
viscosity_data_path
]
autosave_density_filepaths = [
density_data_path
]
autosave_id_filepaths = [
id_data_path
]
autosave_diffuse_filepaths = [
diffuse_position_data_path,
diffuse_velocity_data_path,
diffuse_lifetime_data_path,
diffuse_type_data_path,
diffuse_id_data_path
]
num_particles = fluidsim.get_num_marker_particles()
marker_particles_per_write = 2**21
num_marker_particle_writes = (num_particles // marker_particles_per_write) + 1
try:
for i in range(num_marker_particle_writes):
start_idx = i * marker_particles_per_write
end_idx = min((i + 1) * marker_particles_per_write, num_particles)
is_appending = i != 0
data = fluidsim.get_marker_particle_position_data_range(start_idx, end_idx)
__write_save_state_file_data(position_data_path + temp_extension, data, is_appending_data=is_appending)
data = fluidsim.get_marker_particle_velocity_data_range(start_idx, end_idx)
__write_save_state_file_data(velocity_data_path + temp_extension, data, is_appending_data=is_appending)
if fluidsim.is_velocity_transfer_method_APIC():
data = fluidsim.get_marker_particle_affinex_data_range(start_idx, end_idx)
__write_save_state_file_data(affinex_data_path + temp_extension, data, is_appending_data=is_appending)
data = fluidsim.get_marker_particle_affiney_data_range(start_idx, end_idx)
__write_save_state_file_data(affiney_data_path + temp_extension, data, is_appending_data=is_appending)
data = fluidsim.get_marker_particle_affinez_data_range(start_idx, end_idx)
__write_save_state_file_data(affinez_data_path + temp_extension, data, is_appending_data=is_appending)
if fluidsim.enable_surface_age_attribute or fluidsim.enable_fluid_particle_age_attribute:
data = fluidsim.get_marker_particle_age_data_range(start_idx, end_idx)
__write_save_state_file_data(age_data_path + temp_extension, data, is_appending_data=is_appending)
if fluidsim.enable_surface_lifetime_attribute or fluidsim.enable_fluid_particle_lifetime_attribute:
data = fluidsim.get_marker_particle_lifetime_data_range(start_idx, end_idx)
__write_save_state_file_data(lifetime_data_path + temp_extension, data, is_appending_data=is_appending)
if fluidsim.enable_surface_color_attribute or fluidsim.enable_fluid_particle_color_attribute:
data = fluidsim.get_marker_particle_color_data_range(start_idx, end_idx)
__write_save_state_file_data(color_data_path + temp_extension, data, is_appending_data=is_appending)
if fluidsim.enable_surface_source_id_attribute or fluidsim.enable_fluid_particle_source_id_attribute:
data = fluidsim.get_marker_particle_source_id_data_range(start_idx, end_idx)
__write_save_state_file_data(source_id_data_path + temp_extension, data, is_appending_data=is_appending)
if fluidsim.enable_fluid_particle_uid_attribute:
data = fluidsim.get_marker_particle_uid_data_range(start_idx, end_idx)
__write_save_state_file_data(uid_data_path + temp_extension, data, is_appending_data=is_appending)
if fluidsim.enable_surface_viscosity_attribute:
data = fluidsim.get_marker_particle_viscosity_data_range(start_idx, end_idx)
__write_save_state_file_data(viscosity_data_path + temp_extension, data, is_appending_data=is_appending)
if fluidsim.enable_surface_density_attribute or fluidsim.enable_fluid_particle_density_attribute:
data = fluidsim.get_marker_particle_density_data_range(start_idx, end_idx)
__write_save_state_file_data(density_data_path + temp_extension, data, is_appending_data=is_appending)
if fluidsim.enable_fluid_particle_output:
data = fluidsim.get_marker_particle_id_data_range(start_idx, end_idx)
__write_save_state_file_data(id_data_path + temp_extension, data, is_appending_data=is_appending)
if fluidsim.get_num_diffuse_particles() > 0:
num_particles = fluidsim.get_num_diffuse_particles()
diffuse_particles_per_write = 2**21
num_diffuse_particle_writes = (num_particles // diffuse_particles_per_write) + 1
for i in range(num_diffuse_particle_writes):
start_idx = i * diffuse_particles_per_write
end_idx = min((i + 1) * diffuse_particles_per_write, num_particles)
is_appending = i != 0
data = fluidsim.get_diffuse_particle_position_data_range(start_idx, end_idx)
__write_save_state_file_data(diffuse_position_data_path + temp_extension, data, is_appending_data=is_appending)
data = fluidsim.get_diffuse_particle_velocity_data_range(start_idx, end_idx)
__write_save_state_file_data(diffuse_velocity_data_path + temp_extension, data, is_appending_data=is_appending)
data = fluidsim.get_diffuse_particle_lifetime_data_range(start_idx, end_idx)
__write_save_state_file_data(diffuse_lifetime_data_path + temp_extension, data, is_appending_data=is_appending)
data = fluidsim.get_diffuse_particle_type_data_range(start_idx, end_idx)
__write_save_state_file_data(diffuse_type_data_path + temp_extension, data, is_appending_data=is_appending)
data = fluidsim.get_diffuse_particle_id_data_range(start_idx, end_idx)
__write_save_state_file_data(diffuse_id_data_path + temp_extension, data, is_appending_data=is_appending)
init_data = domain_data.initialize
frame_start, frame_end = init_data.frame_start, init_data.frame_end
autosave_info = {}
autosave_info['isize'] = init_data.isize
autosave_info['jsize'] = init_data.jsize
autosave_info['ksize'] = init_data.ksize
autosave_info['dx'] = init_data.dx
autosave_info['frame'] = frameno
autosave_info['frame_start'] = frame_start
autosave_info['frame_end'] = frame_end
autosave_info['frame_id'] = fluidsim.get_current_frame() - 1
autosave_info['last_frame_id'] = frame_end - frame_start
autosave_info['num_marker_particles'] = fluidsim.get_num_marker_particles()
autosave_info['current_fluid_particle_uid'] = str(fluidsim.get_current_fluid_particle_uid())
autosave_info['marker_particle_position_filedata'] = "marker_particle_position.data"
autosave_info['marker_particle_velocity_filedata'] = "marker_particle_velocity.data"
autosave_info['num_diffuse_particles'] = fluidsim.get_num_diffuse_particles()
autosave_info['marker_particle_affinex_filedata'] = ""
autosave_info['marker_particle_affiney_filedata'] = ""
autosave_info['marker_particle_affinez_filedata'] = ""
autosave_info['marker_particle_age_filedata'] = ""
autosave_info['marker_particle_lifetime_filedata'] = ""
autosave_info['marker_particle_color_filedata'] = ""
autosave_info['marker_particle_source_id_filedata'] = ""
autosave_info['marker_particle_uid_filedata'] = ""
autosave_info['marker_particle_viscosity_filedata'] = ""
autosave_info['marker_particle_density_filedata'] = ""
autosave_info['marker_particle_id_filedata'] = ""
autosave_info['diffuse_particle_position_filedata'] = ""
autosave_info['diffuse_particle_velocity_filedata'] = ""
autosave_info['diffuse_particle_lifetime_filedata'] = ""
autosave_info['diffuse_particle_type_filedata'] = ""
autosave_info['diffuse_particle_id_filedata'] = ""
if fluidsim.is_velocity_transfer_method_APIC():
autosave_info['marker_particle_affinex_filedata'] = "marker_particle_affinex.data"
autosave_info['marker_particle_affiney_filedata'] = "marker_particle_affiney.data"
autosave_info['marker_particle_affinez_filedata'] = "marker_particle_affinez.data"
if fluidsim.enable_surface_age_attribute or fluidsim.enable_fluid_particle_age_attribute:
autosave_info['marker_particle_age_filedata'] = "marker_particle_age.data"
if fluidsim.enable_surface_lifetime_attribute or fluidsim.enable_fluid_particle_lifetime_attribute:
autosave_info['marker_particle_lifetime_filedata'] = "marker_particle_lifetime.data"
if fluidsim.enable_surface_color_attribute or fluidsim.enable_fluid_particle_color_attribute:
autosave_info['marker_particle_color_filedata'] = "marker_particle_color.data"
if fluidsim.enable_surface_source_id_attribute or fluidsim.enable_fluid_particle_source_id_attribute:
autosave_info['marker_particle_source_id_filedata'] = "marker_particle_source_id.data"
if fluidsim.enable_fluid_particle_uid_attribute:
autosave_info['marker_particle_uid_filedata'] = "marker_particle_uid.data"
if fluidsim.enable_surface_viscosity_attribute:
autosave_info['marker_particle_viscosity_filedata'] = "marker_particle_viscosity.data"
if fluidsim.enable_surface_density_attribute or fluidsim.enable_fluid_particle_density_attribute:
autosave_info['marker_particle_density_filedata'] = "marker_particle_density.data"
if fluidsim.enable_fluid_particle_output:
autosave_info['marker_particle_id_filedata'] = "marker_particle_id.data"
if fluidsim.get_num_diffuse_particles() > 0:
autosave_info['diffuse_particle_position_filedata'] = "diffuse_particle_position.data"
autosave_info['diffuse_particle_velocity_filedata'] = "diffuse_particle_velocity.data"
autosave_info['diffuse_particle_lifetime_filedata'] = "diffuse_particle_lifetime.data"
autosave_info['diffuse_particle_type_filedata'] = "diffuse_particle_type.data"
autosave_info['diffuse_particle_id_filedata'] = "diffuse_particle_id.data"
autosave_json = json.dumps(autosave_info, sort_keys=True, indent=4)
with open(autosave_info_path + temp_extension, 'w', encoding='utf-8') as f:
f.write(autosave_json)
except Exception as e:
print("FLIP Fluids: OS/Filesystem Error: Unable to write autosave files to storage")
print("Error Message: ", e)
print("Backup of the last successful autosave located here: <" + autosave_dir + ">")
return
try:
data_filepaths = (
autosave_default_filepaths +
autosave_apic_filepaths +
autosave_age_filepaths +
autosave_lifetime_filepaths +
autosave_color_filepaths +
autosave_source_id_filepaths +
autosave_uid_filepaths +
autosave_viscosity_filepaths +
autosave_density_filepaths +
autosave_id_filepaths +
autosave_diffuse_filepaths
)
for filepath in data_filepaths:
if os.path.isfile(filepath):
fpl.delete_file(filepath, display_popup_on_error=False)
except Exception as e:
print("FLIP Fluids: OS/Filesystem Error: Unable to delete older autosave files from storage")
print("Error Message: ", e)
print("Backup of the last successful autosave located here: <" + autosave_dir + ">")
return
try:
for filepath in autosave_default_filepaths:
os.rename(filepath + temp_extension, filepath)
if fluidsim.is_velocity_transfer_method_APIC():
for filepath in autosave_apic_filepaths:
os.rename(filepath + temp_extension, filepath)
if fluidsim.enable_surface_age_attribute or fluidsim.enable_fluid_particle_age_attribute:
for filepath in autosave_age_filepaths:
os.rename(filepath + temp_extension, filepath)
if fluidsim.enable_surface_lifetime_attribute or fluidsim.enable_fluid_particle_lifetime_attribute:
for filepath in autosave_lifetime_filepaths:
os.rename(filepath + temp_extension, filepath)
if fluidsim.enable_surface_color_attribute or fluidsim.enable_fluid_particle_color_attribute:
for filepath in autosave_color_filepaths:
os.rename(filepath + temp_extension, filepath)
if fluidsim.enable_surface_source_id_attribute or fluidsim.enable_fluid_particle_source_id_attribute:
for filepath in autosave_source_id_filepaths:
os.rename(filepath + temp_extension, filepath)
if fluidsim.enable_fluid_particle_uid_attribute:
for filepath in autosave_uid_filepaths:
os.rename(filepath + temp_extension, filepath)
if fluidsim.enable_surface_viscosity_attribute:
for filepath in autosave_viscosity_filepaths:
os.rename(filepath + temp_extension, filepath)
if fluidsim.enable_surface_density_attribute or fluidsim.enable_fluid_particle_density_attribute:
for filepath in autosave_density_filepaths:
os.rename(filepath + temp_extension, filepath)
if fluidsim.enable_fluid_particle_output:
for filepath in autosave_id_filepaths:
os.rename(filepath + temp_extension, filepath)
if fluidsim.get_num_diffuse_particles() > 0:
for filepath in autosave_diffuse_filepaths:
os.rename(filepath + temp_extension, filepath)
except Exception as e:
print("FLIP Fluids: OS/Filesystem Error: Unable to rename autosave files in storage")
print("Error Message: ", e)
print("Backup of the last successful autosave located here: <" + autosave_dir + ">")
return
init_data = domain_data.initialize
if init_data.enable_savestates:
interval = init_data.savestate_interval
if (frameno + 1 - frame_start) % interval == 0 or frameno == frame_start:
numstr = str(frameno).zfill(6)
savestate_dir = os.path.join(cache_directory, "savestates", "autosave" + numstr)
if os.path.isdir(savestate_dir):
fpl.delete_files_in_directory(
savestate_dir, [".state", ".data"],
remove_directory=True,
display_popup_on_error=False
)
shutil.copytree(autosave_dir, savestate_dir, dirs_exist_ok=True)
def __write_finished_file(cache_directory, frameno):
fstring = __frame_number_to_string(frameno)
finished_filename = "finished" + fstring + ".txt"
finished_filepath = os.path.join(cache_directory, "bakefiles", finished_filename)
filestring = fstring
with open(finished_filepath, 'w') as f:
f.write(filestring)
def __write_metadata_file(domain_data, cache_directory, frameno):
fstring = __frame_number_to_string(frameno)
metadata_filename = "metadata" + fstring + ".json"
metadata_filepath = os.path.join(cache_directory, "bakefiles", metadata_filename)
simdata = domain_data.simulation
frame_id = __get_frame_id() - 1
data_dict = {}
data_dict['time_scale'] = __get_parameter_data(simdata.time_scale, frame_id)
data_dict['world_scale'] = __get_parameter_data(domain_data.world.world_scale_relative, frame_id)
json_string = json.dumps(data_dict)
with open(metadata_filepath, 'w') as f:
f.write(json_string)
def __write_simulation_output(domain_data, fluidsim, frameno, cache_directory):
__write_bounds_data(cache_directory, fluidsim, frameno)
if fluidsim.enable_surface_reconstruction:
__write_surface_data(cache_directory, fluidsim, frameno)
if fluidsim.enable_diffuse_material_output:
__write_whitewater_data(cache_directory, fluidsim, frameno)
if fluidsim.enable_fluid_particle_output:
__write_fluid_particle_data(cache_directory, fluidsim, frameno)
if fluidsim.enable_fluid_particle_debug_output:
__write_fluid_particle_debug_data(cache_directory, fluidsim, frameno)
if fluidsim.enable_internal_obstacle_mesh_output:
__write_internal_obstacle_mesh_data(cache_directory, fluidsim, frameno)
if fluidsim.enable_force_field_debug_output:
__write_force_field_debug_data(cache_directory, fluidsim, frameno)
__write_logfile_data(cache_directory, domain_data.initialize.logfile_name, fluidsim)
__write_frame_stats_data(cache_directory, fluidsim, frameno)
__write_autosave_data(domain_data, cache_directory, fluidsim, frameno)
__write_metadata_file(domain_data, cache_directory, frameno)
__write_finished_file(cache_directory, frameno)
def __get_current_frame_delta_time(domain_data, frameno):
simdata = domain_data.simulation
init_data = domain_data.initialize
time_scale = __get_parameter_data(simdata.time_scale, frameno)
fps = __get_parameter_data(simdata.frames_per_second, frameno)
dt = (1.0 / fps) * time_scale
return dt
def __run_simulation(fluidsim, data, cache_directory, bakedata):
domain = data.domain_data
init_data = domain.initialize
num_frames = init_data.frame_end - init_data.frame_start + 1
current_frame = fluidsim.get_current_frame()
for i in range(current_frame, num_frames):
simulator_frameno = fluidsim.get_current_frame()
blender_frameno = simulator_frameno + init_data.frame_start
geometry_database = __get_geometry_database()
try:
geometry_database.open()
__update_animatable_properties(fluidsim, data, simulator_frameno)
__add_fluid_objects(fluidsim, data, bakedata, simulator_frameno)
geometry_database.close()
except Exception:
geometry_database.close()
raise Exception
dt = __get_current_frame_delta_time(domain, simulator_frameno)
fluidsim.update(dt)
if __check_bake_cancelled(bakedata):
return
bakedata.is_safe_to_exit = False
__write_simulation_output(domain, fluidsim, blender_frameno, cache_directory)
bakedata.is_safe_to_exit = True
bakedata.completed_frames = simulator_frameno + 1
bakedata.progress = (simulator_frameno + 1) / num_frames
if __check_bake_cancelled(bakedata):
return
def set_console_output(boolval):
fluidsim_object = __get_simulation_object()
if fluidsim_object is None or fluidsim_object._obj is None:
return
old_value = fluidsim_object.enable_console_output
if fluidsim_object.enable_console_output == boolval:
return
fluidsim_object.enable_console_output = boolval
def __get_addon_version():
bl_info_dict = bl_info
addon_major, addon_minor, addon_revision = bl_info_dict.get('version', (-1, -1, -1))
return str(addon_major) + "." + str(addon_minor) + "." + str(addon_revision)
def __get_engine_version(fluidsim):
engine_major, engine_minor, engine_revision = fluidsim.get_version()
return str(engine_major) + "." + str(engine_minor) + "." + str(engine_revision)
def __launch_bake(datafile, cache_directory, bakedata, savestate_id=None):
__set_cache_directory(cache_directory)
data = __extract_data(datafile)
__set_simulation_data(data)
db_filepath = __get_geometry_database_filepath()
geometry_database = flip_fluid_geometry_database.GeometryDatabase(db_filepath)
__set_geometry_database(geometry_database)
if __check_bake_cancelled(bakedata):
return
__set_output_directories(cache_directory)
init_data = data.domain_data.initialize
fluidsim = FluidSimulation(init_data.isize, init_data.jsize, init_data.ksize, init_data.dx)
__set_simulation_object(fluidsim)
if __get_addon_version() != __get_engine_version(fluidsim):
errmsg = "The FLIP Fluids engine version <" + __get_engine_version(fluidsim)
errmsg += "> is not compatible with the addon version <" + __get_addon_version() + ">."
errmsg += " Blender may require a restart if you have updated the addon to a new version during this session"
raise LibraryVersionError(errmsg)
if __check_bake_cancelled(bakedata):
return
geometry_database.open()
__initialize_fluid_simulation(fluidsim, data, cache_directory, bakedata, savestate_id)
geometry_database.close()
if __check_bake_cancelled(bakedata):
return
__run_simulation(fluidsim, data, cache_directory, bakedata)
def bake(datafile, cache_directory, bakedata, savestate_id=None, bake_retries=0):
max_baking_retries = bake_retries
for retry_num in range(max_baking_retries + 1):
try:
__launch_bake(datafile, cache_directory, bakedata, savestate_id)
print("------------------------------------------------------------")
print("Simulation Ended.\nThank you for using FLIP Fluids!")
print("------------------------------------------------------------")
break
except Exception as e:
database = __get_geometry_database()
database.close()
error_string = str(e)
errmsg = error_string
do_not_attempt_relaunch = False
if "std::bad_alloc" in errmsg:
errmsg = "Out of memory. "
elif "No space left on device" in errmsg:
do_not_attempt_relaunch = True
elif not errmsg:
errmsg = "Unknown error. "
if not errmsg.endswith(". "):
errmsg += ". "
errmsg += "See system console for error info."
traceback.print_exc()
print("------------------------------------------------------------")
print("SIMULATION TERMINATED DUE TO ERROR:")
if "std::bad_alloc" in error_string:
print("\tOut of Memory")
else:
print("\t" + error_string)
print("\nThank you for using FLIP Fluids!")
print("------------------------------------------------------------")
if retry_num == max_baking_retries or do_not_attempt_relaunch:
bakedata.error_message = errmsg
break
else:
# Setting to a negative value will default to the most recent savestate on the next attempt.
savestate_id = -1
retry_msg = "Attempting to re-launch bake... "
retry_msg += "(retry attempt " + str(retry_num + 1) + "/" + str(max_baking_retries) + ")"
print(retry_msg)
__set_simulation_object(None)
bakedata.is_finished = True