2026-02-16

This commit is contained in:
2026-03-17 15:25:32 -06:00
parent d5dd373de0
commit 60100fbab2
560 changed files with 33397 additions and 20776 deletions
@@ -16,10 +16,10 @@
bl_info = {
"name" : "FLIP Fluids",
"description": "A FLIP Fluid Simulation Tool for Blender (v1.8.4 Release 2025-07-17)",
"description": "A FLIP Fluid Simulation Tool for Blender (v1.8.5 Release 2025-11-18)",
"author" : "Ryan Guy & Dennis Fassbaender <support[at]flipfluids.com>",
"version" : (1, 8, 4),
"blender" : (3, 6, 0),
"version" : (1, 8, 5),
"blender" : (4, 5, 0),
"location" : "Properties > Physics > FLIP Fluid",
"warning" : "",
"wiki_url" : "https://github.com/rlguy/Blender-FLIP-Fluids/wiki",
@@ -147,9 +147,6 @@ def load_post(nonedata):
if bpy.context.scene.flip_fluid.is_addon_disabled_in_blend_file():
return
if vcu.is_blender_28() and not vcu.is_blender_281():
print("FLIP FLUIDS WARNING: Blender 2.80 contains bugs that can cause frequent crashes during render, Alembic export, and rigid/cloth simulation baking. Blender version 2.81 or higher is recommended.")
installation_utils.load_post()
materials.load_post()
properties.load_post()
@@ -202,11 +199,7 @@ def register():
ui.register()
presets.register()
if vcu.is_blender_28():
bpy.app.handlers.depsgraph_update_post.append(scene_update_post)
else:
bpy.app.handlers.scene_update_post.append(scene_update_post)
bpy.app.handlers.depsgraph_update_post.append(scene_update_post)
bpy.app.handlers.render_init.append(render_init)
bpy.app.handlers.render_complete.append(render_complete)
bpy.app.handlers.render_cancel.append(render_cancel)
@@ -230,11 +223,7 @@ def unregister():
ui.unregister()
presets.unregister()
if vcu.is_blender_28():
bpy.app.handlers.depsgraph_update_post.remove(scene_update_post)
else:
bpy.app.handlers.scene_update_post.remove(scene_update_post)
bpy.app.handlers.depsgraph_update_post.remove(scene_update_post)
bpy.app.handlers.render_init.remove(render_init)
bpy.app.handlers.render_complete.remove(render_complete)
bpy.app.handlers.render_cancel.remove(render_cancel)
@@ -16,10 +16,10 @@
bl_info = {
"name" : "FLIP Fluids",
"description": "A FLIP Fluid Simulation Tool for Blender (v@FLUIDENGINE_VERSION_LABEL@)",
"description": "A FLIP Fluid Simulation Tool for Blender (v@FFENGINE_VERSION_LABEL@)",
"author" : "Ryan Guy & Dennis Fassbaender <support[at]flipfluids.com>",
"version" : (@FLUIDENGINE_VERSION_MAJOR@, @FLUIDENGINE_VERSION_MINOR@, @FLUIDENGINE_VERSION_REVISION@),
"blender" : (3, 6, 0),
"version" : (@FFENGINE_VERSION_MAJOR@, @FFENGINE_VERSION_MINOR@, @FFENGINE_VERSION_REVISION@),
"blender" : (4, 5, 0),
"location" : "Properties > Physics > FLIP Fluid",
"warning" : "",
"wiki_url" : "https://github.com/rlguy/Blender-FLIP-Fluids/wiki",
@@ -147,9 +147,6 @@ def load_post(nonedata):
if bpy.context.scene.flip_fluid.is_addon_disabled_in_blend_file():
return
if vcu.is_blender_28() and not vcu.is_blender_281():
print("FLIP FLUIDS WARNING: Blender 2.80 contains bugs that can cause frequent crashes during render, Alembic export, and rigid/cloth simulation baking. Blender version 2.81 or higher is recommended.")
installation_utils.load_post()
materials.load_post()
properties.load_post()
@@ -202,11 +199,7 @@ def register():
ui.register()
presets.register()
if vcu.is_blender_28():
bpy.app.handlers.depsgraph_update_post.append(scene_update_post)
else:
bpy.app.handlers.scene_update_post.append(scene_update_post)
bpy.app.handlers.depsgraph_update_post.append(scene_update_post)
bpy.app.handlers.render_init.append(render_init)
bpy.app.handlers.render_complete.append(render_complete)
bpy.app.handlers.render_cancel.append(render_cancel)
@@ -230,11 +223,7 @@ def unregister():
ui.unregister()
presets.unregister()
if vcu.is_blender_28():
bpy.app.handlers.depsgraph_update_post.remove(scene_update_post)
else:
bpy.app.handlers.scene_update_post.remove(scene_update_post)
bpy.app.handlers.depsgraph_update_post.remove(scene_update_post)
bpy.app.handlers.render_init.remove(render_init)
bpy.app.handlers.render_complete.remove(render_complete)
bpy.app.handlers.render_cancel.remove(render_cancel)
+105 -48
View File
@@ -635,6 +635,15 @@ def __load_save_state_marker_particle_data(fluidsim, save_state_directory, autos
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:
@@ -703,6 +712,10 @@ def __load_save_state_marker_particle_data(fluidsim, save_state_directory, autos
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)
@@ -1178,6 +1191,9 @@ def __initialize_fluid_simulation_settings(fluidsim, data):
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
@@ -1199,10 +1215,8 @@ def __initialize_fluid_simulation_settings(fluidsim, data):
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)
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
@@ -1217,47 +1231,30 @@ def __initialize_fluid_simulation_settings(fluidsim, data):
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_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)
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)
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)
@@ -1271,8 +1268,9 @@ def __initialize_fluid_simulation_settings(fluidsim, data):
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_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)
@@ -1495,6 +1493,7 @@ def __add_fluid_objects(fluidsim, data, bakedata, frameid=0):
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))
@@ -1693,6 +1692,7 @@ def __update_animatable_inflow_properties(data, mesh_geometry_data, frameid):
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))
@@ -2392,6 +2392,13 @@ def __write_surface_data(cache_directory, fluidsim, frameno):
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()
@@ -2592,6 +2599,22 @@ def __write_fluid_particle_data(cache_directory, fluidsim, frameno):
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)
@@ -2710,6 +2733,7 @@ def __get_frame_stats_dict(cstats):
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)
@@ -2740,6 +2764,11 @@ def __get_frame_stats_dict(cstats):
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)
@@ -2779,6 +2808,7 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno):
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")
@@ -2817,6 +2847,9 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno):
autosave_viscosity_filepaths = [
viscosity_data_path
]
autosave_density_filepaths = [
density_data_path
]
autosave_id_filepaths = [
id_data_path
]
@@ -2875,6 +2908,10 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno):
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)
@@ -2929,6 +2966,7 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno):
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'] = ""
@@ -2960,6 +2998,9 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno):
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"
@@ -2990,6 +3031,7 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno):
autosave_source_id_filepaths +
autosave_uid_filepaths +
autosave_viscosity_filepaths +
autosave_density_filepaths +
autosave_id_filepaths +
autosave_diffuse_filepaths
)
@@ -3026,6 +3068,9 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno):
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)
@@ -3062,6 +3107,24 @@ def __write_finished_file(cache_directory, frameno):
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)
@@ -3086,6 +3149,7 @@ def __write_simulation_output(domain_data, fluidsim, frameno, cache_directory):
__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)
@@ -3150,14 +3214,7 @@ def set_console_output(boolval):
def __get_addon_version():
if vcu.is_blender_42():
bl_info_dict = bl_info
else:
module_dir = os.path.dirname(os.path.realpath(__file__))
module_name = os.path.basename(os.path.normpath(module_dir))
module = sys.modules[module_name]
bl_info_dict = module.bl_info
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)
@@ -2,13 +2,13 @@ schema_version = "1.0.0"
id = "flip_fluids_addon"
type = "add-on"
version = "1.8.4"
version = "1.8.5"
name = "FLIP Fluids"
tagline = "A FLIP Fluid Simulation Tool for Blender (v1.8.4 Release 2025-07-17)"
tagline = "A FLIP Fluid Simulation Tool for Blender (v1.8.5 Release 2025-11-18)"
maintainer = "Ryan Guy & Dennis Fassbaender // support@flipfluids.com"
website = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki"
tags = ["Animation", "Physics"]
blender_version_min = "4.2.0"
blender_version_min = "4.5.0"
license = ["SPDX:GPL-3.0-or-later"]
platforms = ["windows-x64", "macos-x64", "macos-arm64", "linux-x64"]
@@ -2,13 +2,13 @@ schema_version = "1.0.0"
id = "flip_fluids_addon"
type = "add-on"
version = "@FLUIDENGINE_VERSION_MAJOR@.@FLUIDENGINE_VERSION_MINOR@.@FLUIDENGINE_VERSION_REVISION@"
version = "@FFENGINE_VERSION_MAJOR@.@FFENGINE_VERSION_MINOR@.@FFENGINE_VERSION_REVISION@"
name = "FLIP Fluids"
tagline = "A FLIP Fluid Simulation Tool for Blender (v@FLUIDENGINE_VERSION_LABEL@)"
tagline = "A FLIP Fluid Simulation Tool for Blender (v@FFENGINE_VERSION_LABEL@)"
maintainer = "Ryan Guy & Dennis Fassbaender // support@flipfluids.com"
website = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki"
tags = ["Animation", "Physics"]
blender_version_min = "4.2.0"
blender_version_min = "4.5.0"
license = ["SPDX:GPL-3.0-or-later"]
platforms = ["windows-x64", "macos-x64", "macos-arm64", "linux-x64"]
@@ -834,6 +834,21 @@ class FluidSimulation(object):
pb.init_lib_func(libfunc, [c_void_p, c_void_p], None)
pb.execute_lib_func(libfunc, [self()])
@property
def enable_fluid_particle_density_attribute(self):
libfunc = lib.FluidSimulation_is_fluid_particle_density_attribute_enabled
pb.init_lib_func(libfunc, [c_void_p, c_void_p], c_int)
return bool(pb.execute_lib_func(libfunc, [self()]))
@enable_fluid_particle_density_attribute.setter
def enable_fluid_particle_density_attribute(self, boolval):
if boolval:
libfunc = lib.FluidSimulation_enable_fluid_particle_density_attribute
else:
libfunc = lib.FluidSimulation_disable_fluid_particle_density_attribute
pb.init_lib_func(libfunc, [c_void_p, c_void_p], None)
pb.execute_lib_func(libfunc, [self()])
@property
def enable_fluid_particle_uid_attribute(self):
libfunc = lib.FluidSimulation_is_fluid_particle_uid_attribute_enabled
@@ -1144,6 +1159,21 @@ class FluidSimulation(object):
pb.init_lib_func(libfunc, [c_void_p, c_void_p], None)
pb.execute_lib_func(libfunc, [self()])
@property
def enable_surface_density_attribute(self):
libfunc = lib.FluidSimulation_is_surface_density_attribute_enabled
pb.init_lib_func(libfunc, [c_void_p, c_void_p], c_int)
return bool(pb.execute_lib_func(libfunc, [self()]))
@enable_surface_density_attribute.setter
def enable_surface_density_attribute(self, boolval):
if boolval:
libfunc = lib.FluidSimulation_enable_surface_density_attribute
else:
libfunc = lib.FluidSimulation_disable_surface_density_attribute
pb.init_lib_func(libfunc, [c_void_p, c_void_p], None)
pb.execute_lib_func(libfunc, [self()])
@property
def enable_remove_surface_near_domain(self):
libfunc = lib.FluidSimulation_is_remove_surface_near_domain_enabled
@@ -2750,6 +2780,10 @@ class FluidSimulation(object):
return self._get_output_data(lib.FluidSimulation_get_surface_viscosity_attribute_data_size,
lib.FluidSimulation_get_surface_viscosity_attribute_data)
def get_surface_density_attribute_data(self):
return self._get_output_data(lib.FluidSimulation_get_surface_density_attribute_data_size,
lib.FluidSimulation_get_surface_density_attribute_data)
def get_whitewater_foam_id_attribute_data(self):
return self._get_output_data(lib.FluidSimulation_get_whitewater_foam_id_attribute_data_size,
lib.FluidSimulation_get_whitewater_foam_id_attribute_data)
@@ -2854,6 +2888,14 @@ class FluidSimulation(object):
return self._get_output_data(lib.FluidSimulation_get_fluid_particle_viscosity_attribute_data_size,
lib.FluidSimulation_get_fluid_particle_viscosity_attribute_data)
def get_fluid_particle_density_attribute_data(self):
return self._get_output_data(lib.FluidSimulation_get_fluid_particle_density_attribute_data_size,
lib.FluidSimulation_get_fluid_particle_density_attribute_data)
def get_fluid_particle_density_average_attribute_data(self):
return self._get_output_data(lib.FluidSimulation_get_fluid_particle_density_average_attribute_data_size,
lib.FluidSimulation_get_fluid_particle_density_average_attribute_data)
def get_fluid_particle_whitewater_proximity_attribute_data(self):
return self._get_output_data(lib.FluidSimulation_get_fluid_particle_whitewater_proximity_attribute_data_size,
lib.FluidSimulation_get_fluid_particle_whitewater_proximity_attribute_data)
@@ -2985,6 +3027,11 @@ class FluidSimulation(object):
return self._get_output_data_range(lib.FluidSimulation_get_marker_particle_viscosity_data_range,
start_idx, end_idx, size_of_float)
def get_marker_particle_density_data_range(self, start_idx, end_idx):
size_of_float = 4
return self._get_output_data_range(lib.FluidSimulation_get_marker_particle_density_data_range,
start_idx, end_idx, size_of_float)
def get_marker_particle_id_data_range(self, start_idx, end_idx):
size_of_short = 2
return self._get_output_data_range(lib.FluidSimulation_get_marker_particle_id_data_range,
@@ -3136,6 +3183,17 @@ class FluidSimulation(object):
pb.init_lib_func(libfunc, [c_void_p, FluidSimulationMarkerParticleViscosityData_t, c_void_p], None)
pb.execute_lib_func(libfunc, [self(), pdata])
def load_marker_particle_density_data(self, num_particles, density_data):
c_density_data = (c_char * len(density_data)).from_buffer_copy(density_data)
pdata = FluidSimulationMarkerParticleDensityData_t()
pdata.size = c_int(num_particles)
pdata.density = ctypes.cast(c_density_data, c_char_p)
libfunc = lib.FluidSimulation_load_marker_particle_density_data
pb.init_lib_func(libfunc, [c_void_p, FluidSimulationMarkerParticleDensityData_t, c_void_p], None)
pb.execute_lib_func(libfunc, [self(), pdata])
def load_marker_particle_id_data(self, num_particles, id_data):
c_id_data = (c_char * len(id_data)).from_buffer_copy(id_data)
@@ -3224,6 +3282,7 @@ class FluidSimulationFrameStats_t(ctypes.Structure):
("surfacecolor", FluidSimulationMeshStats_t),
("surfacesourceid", FluidSimulationMeshStats_t),
("surfaceviscosity", FluidSimulationMeshStats_t),
("surfacedensity", FluidSimulationMeshStats_t),
("foam", FluidSimulationMeshStats_t),
("bubble", FluidSimulationMeshStats_t),
("spray", FluidSimulationMeshStats_t),
@@ -3254,6 +3313,8 @@ class FluidSimulationFrameStats_t(ctypes.Structure):
("fluidparticlesage", FluidSimulationMeshStats_t),
("fluidparticleslifetime", FluidSimulationMeshStats_t),
("fluidparticlesviscosity", FluidSimulationMeshStats_t),
("fluidparticlesdensity", FluidSimulationMeshStats_t),
("fluidparticlesdensityaverage", FluidSimulationMeshStats_t),
("fluidparticleswhitewaterproximity", FluidSimulationMeshStats_t),
("fluidparticlessourceid", FluidSimulationMeshStats_t),
("particles", FluidSimulationMeshStats_t),
@@ -3296,6 +3357,10 @@ class FluidSimulationMarkerParticleViscosityData_t(ctypes.Structure):
_fields_ = [("size", c_int),
("viscosity", c_char_p)]
class FluidSimulationMarkerParticleDensityData_t(ctypes.Structure):
_fields_ = [("size", c_int),
("density", c_char_p)]
class FluidSimulationMarkerParticleIDData_t(ctypes.Structure):
_fields_ = [("size", c_int),
("id", c_char_p)]
@@ -258,6 +258,18 @@ class MeshFluidSource():
pb.init_lib_func(libfunc, [c_void_p, c_float, c_void_p], None)
pb.execute_lib_func(libfunc, [self(), float(v)])
@property
def density(self):
libfunc = lib.MeshFluidSource_get_density
pb.init_lib_func(libfunc, [c_void_p, c_void_p], c_int)
return pb.execute_lib_func(libfunc, [self()])
@density.setter
def density(self, v):
libfunc = lib.MeshFluidSource_set_density
pb.init_lib_func(libfunc, [c_void_p, c_float, c_void_p], None)
pb.execute_lib_func(libfunc, [self(), float(v)])
@property
def lifetime(self):
libfunc = lib.MeshFluidSource_get_lifetime
@@ -233,6 +233,18 @@ class MeshObject():
pb.init_lib_func(libfunc, [c_void_p, c_float, c_void_p], None)
pb.execute_lib_func(libfunc, [self(), float(v)])
@property
def density(self):
libfunc = lib.MeshObject_get_density
pb.init_lib_func(libfunc, [c_void_p, c_void_p], c_int)
return pb.execute_lib_func(libfunc, [self()])
@density.setter
def density(self, v):
libfunc = lib.MeshObject_set_density
pb.init_lib_func(libfunc, [c_void_p, c_float, c_void_p], None)
pb.execute_lib_func(libfunc, [self(), float(v)])
@property
def lifetime(self):
libfunc = lib.MeshObject_get_lifetime
@@ -224,7 +224,7 @@ def clear_cache_directory(cache_directory, clear_export=False, clear_logs=False,
delete_file(stats_filepath)
bakefiles_dir = os.path.join(cache_directory, "bakefiles")
extensions = [".bbox", ".bobj", ".data", ".wwp", ".wwf", ".wwi", ".fpd", ".ffd", ".ffp3", ".txt"]
extensions = [".bbox", ".bobj", ".data", ".wwp", ".wwf", ".wwi", ".fpd", ".ffd", ".ffp3", ".txt", ".json"]
delete_files_in_directory(bakefiles_dir, extensions, remove_directory=True)
temp_dir = os.path.join(cache_directory, "temp")
@@ -98,10 +98,9 @@ def __get_non_material_library_enums_by_type():
enums = []
for m in bpy.data.materials:
if not m.flip_fluid_material_library.is_library_material:
if vcu.is_blender_30():
# material preview can be None in Blender 3.0. Use the preview_ensure function
# to make sure the preview is loaded
m.preview_ensure()
# material preview can be None in Blender 3.0+. Use the preview_ensure function
# to make sure the preview is loaded
m.preview_ensure()
e = (m.name, m.name, "", m.preview.icon_id, __get_non_material_library_material_hash(m))
enums.append(e)
return enums
@@ -44,18 +44,17 @@ class EnabledMeshCacheObjects:
class FLIPFluidMeshBounds(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
x = FloatProperty(0.0); exec(conv("x"))
y = FloatProperty(0.0); exec(conv("y"))
z = FloatProperty(0.0); exec(conv("z"))
width = FloatProperty(1.0); exec(conv("width"))
height = FloatProperty(1.0); exec(conv("height"))
depth = FloatProperty(1.0); exec(conv("depth"))
dx = FloatProperty(1.0); exec(conv("dx"))
isize = IntProperty(0); exec(conv("isize"))
jsize = IntProperty(0); exec(conv("jsize"))
ksize = IntProperty(0); exec(conv("ksize"))
is_set = BoolProperty(False); exec(conv("is_set"))
x: FloatProperty(0.0)
y: FloatProperty(0.0)
z: FloatProperty(0.0)
width: FloatProperty(1.0)
height: FloatProperty(1.0)
depth: FloatProperty(1.0)
dx: FloatProperty(1.0)
isize: IntProperty(0)
jsize: IntProperty(0)
ksize: IntProperty(0)
is_set: BoolProperty(False)
def set(self, bounds_dict):
@@ -80,27 +79,27 @@ class FLIPFluidMeshBounds(bpy.types.PropertyGroup):
class FlipFluidLoadedMeshData(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
mesh_prefix = StringProperty(default="mesh_prefix"); exec(conv("mesh_prefix"))
enable_motion_blur = BoolProperty(default=False); exec(conv("enable_motion_blur"))
motion_blur_scale = FloatProperty(default=-1.0); exec(conv("motion_blur_scale"))
enable_velocity_attribute = BoolProperty(default=False); exec(conv("enable_velocity_attribute"))
enable_vorticity_attribute = BoolProperty(default=False); exec(conv("enable_vorticity_attribute"))
enable_speed_attribute = BoolProperty(default=False); exec(conv("enable_speed_attribute"))
enable_age_attribute = BoolProperty(default=False); exec(conv("enable_age_attribute"))
enable_color_attribute = BoolProperty(default=False); exec(conv("enable_color_attribute"))
enable_source_id_attribute = BoolProperty(default=False); exec(conv("enable_source_id_attribute"))
enable_viscosity_attribute = BoolProperty(default=False); exec(conv("enable_viscosity_attribute"))
enable_id_attribute = BoolProperty(default=False); exec(conv("enable_id_attribute"))
enable_uid_attribute = BoolProperty(default=False); exec(conv("enable_uid_attribute"))
enable_lifetime_attribute = BoolProperty(default=False); exec(conv("enable_lifetime_attribute"))
enable_whitewater_proximity_attribute = BoolProperty(default=False); exec(conv("enable_whitewater_proximity_attribute"))
wwp_import_percentage = IntProperty(default=0); exec(conv("wwp_import_percentage"))
ffp3_surface_import_percentage = FloatProperty(default=0); exec(conv("ffp3_surface_import_percentage"))
ffp3_boundary_import_percentage = FloatProperty(default=0); exec(conv("ffp3_boundary_import_percentage"))
ffp3_interior_import_percentage = FloatProperty(default=0); exec(conv("ffp3_interior_import_percentage"))
is_rendering = BoolProperty(default=True); exec(conv("is_rendering"))
frame = IntProperty(default=-1); exec(conv("frame"))
mesh_prefix: StringProperty(default="mesh_prefix")
enable_motion_blur: BoolProperty(default=False)
motion_blur_scale: FloatProperty(default=-1.0)
enable_velocity_attribute: BoolProperty(default=False)
enable_vorticity_attribute: BoolProperty(default=False)
enable_speed_attribute: BoolProperty(default=False)
enable_age_attribute: BoolProperty(default=False)
enable_color_attribute: BoolProperty(default=False)
enable_source_id_attribute: BoolProperty(default=False)
enable_viscosity_attribute: BoolProperty(default=False)
enable_density_attribute: BoolProperty(default=False)
enable_id_attribute: BoolProperty(default=False)
enable_uid_attribute: BoolProperty(default=False)
enable_lifetime_attribute: BoolProperty(default=False)
enable_whitewater_proximity_attribute: BoolProperty(default=False)
wwp_import_percentage: IntProperty(default=0)
ffp3_surface_import_percentage: FloatProperty(default=0)
ffp3_boundary_import_percentage: FloatProperty(default=0)
ffp3_interior_import_percentage: FloatProperty(default=0)
is_rendering: BoolProperty(default=True)
frame: IntProperty(default=-1)
def reset(self):
@@ -114,6 +113,7 @@ class FlipFluidLoadedMeshData(bpy.types.PropertyGroup):
self.property_unset("enable_color_attribute")
self.property_unset("enable_source_id_attribute")
self.property_unset("enable_viscosity_attribute")
self.property_unset("enable_density_attribute")
self.property_unset("enable_id_attribute")
self.property_unset("enable_uid_attribute")
self.property_unset("enable_lifetime_attribute")
@@ -127,39 +127,39 @@ class FlipFluidLoadedMeshData(bpy.types.PropertyGroup):
class FlipFluidMeshCache(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
# Mesh properties
mesh_prefix = StringProperty(default=""); exec(conv("mesh_prefix"))
mesh_display_name_prefix = StringProperty(default=""); exec(conv("mesh_display_name_prefix"))
mesh_file_extension = StringProperty(default=""); exec(conv("mesh_file_extension"))
enable_motion_blur = BoolProperty(default=False); exec(conv("enable_motion_blur"))
motion_blur_scale = FloatProperty(default=1.0); exec(conv("motion_blur_scale"))
enable_velocity_attribute = BoolProperty(default=False); exec(conv("enable_velocity_attribute"))
enable_vorticity_attribute = BoolProperty(default=False); exec(conv("enable_vorticity_attribute"))
enable_speed_attribute = BoolProperty(default=False); exec(conv("enable_speed_attribute"))
enable_age_attribute = BoolProperty(default=False); exec(conv("enable_age_attribute"))
enable_color_attribute = BoolProperty(default=False); exec(conv("enable_color_attribute"))
enable_source_id_attribute = BoolProperty(default=False); exec(conv("enable_source_id_attribute"))
enable_viscosity_attribute = BoolProperty(default=False); exec(conv("enable_viscosity_attribute"))
enable_id_attribute = BoolProperty(default=False); exec(conv("enable_id_attribute"))
enable_uid_attribute = BoolProperty(default=False); exec(conv("enable_uid_attribute"))
enable_lifetime_attribute = BoolProperty(default=False); exec(conv("enable_lifetime_attribute"))
enable_whitewater_proximity_attribute = BoolProperty(default=False); exec(conv("enable_whitewater_proximity_attribute"))
cache_object_default_name = StringProperty(default=""); exec(conv("cache_object_default_name"))
cache_object = PointerProperty(type=bpy.types.Object); exec(conv("cache_object"))
is_mesh_shading_smooth = BoolProperty(default=True); exec(conv("is_mesh_shading_smooth"))
current_loaded_frame = IntProperty(default=-1); exec(conv("current_loaded_frame"))
import_function_name = StringProperty(default="import_empty"); exec(conv("import_function_name"))
wwp_import_percentage = IntProperty(default=100); exec(conv("wwp_import_percentage"))
ffp3_surface_import_percentage = FloatProperty(default=0); exec(conv("ffp3_surface_import_percentage"))
ffp3_boundary_import_percentage = FloatProperty(default=0); exec(conv("ffp3_boundary_import_percentage"))
ffp3_interior_import_percentage = FloatProperty(default=0); exec(conv("ffp3_interior_import_percentage"))
cache_object_type = StringProperty(default="CACHE_OBJECT_TYPE_NONE"); exec(conv("cache_object_type"))
mesh_prefix: StringProperty(default="")
mesh_display_name_prefix: StringProperty(default="")
mesh_file_extension: StringProperty(default="")
enable_motion_blur: BoolProperty(default=False)
motion_blur_scale: FloatProperty(default=1.0)
enable_velocity_attribute: BoolProperty(default=False)
enable_vorticity_attribute: BoolProperty(default=False)
enable_speed_attribute: BoolProperty(default=False)
enable_age_attribute: BoolProperty(default=False)
enable_color_attribute: BoolProperty(default=False)
enable_source_id_attribute: BoolProperty(default=False)
enable_viscosity_attribute: BoolProperty(default=False)
enable_density_attribute: BoolProperty(default=False)
enable_id_attribute: BoolProperty(default=False)
enable_uid_attribute: BoolProperty(default=False)
enable_lifetime_attribute: BoolProperty(default=False)
enable_whitewater_proximity_attribute: BoolProperty(default=False)
cache_object_default_name: StringProperty(default="")
cache_object: PointerProperty(type=bpy.types.Object)
is_mesh_shading_smooth: BoolProperty(default=True)
current_loaded_frame: IntProperty(default=-1)
import_function_name: StringProperty(default="import_empty")
wwp_import_percentage: IntProperty(default=100)
ffp3_surface_import_percentage: FloatProperty(default=0)
ffp3_boundary_import_percentage: FloatProperty(default=0)
ffp3_interior_import_percentage: FloatProperty(default=0)
cache_object_type: StringProperty(default="CACHE_OBJECT_TYPE_NONE")
# Loaded data properties
loaded_frame_data = PointerProperty(type=FlipFluidLoadedMeshData); exec(conv("loaded_frame_data"))
bounds = PointerProperty(type=FLIPFluidMeshBounds); exec(conv("bounds"))
loaded_frame_data: PointerProperty(type=FlipFluidLoadedMeshData)
bounds: PointerProperty(type=FLIPFluidMeshBounds)
def _get_cycles_use_motion_blur(self, bl_object):
@@ -194,18 +194,20 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
resource_filepath = os.path.join(parent_path, "resources", "geometry_nodes", blend_resource_filename)
gn_modifier = helper_operators.add_geometry_node_modifier(bl_cache_object, resource_filepath, "FF_GeometryNodesSurface")
bl_domain_object = bpy.context.scene.flip_fluid.get_domain_object()
# Depending on FLIP Fluids version, the GN set up may not
# have these inputs. Available in FLIP Fluids 1.7.2 or later.
key_value_pairs = [
("Input_2_use_attribute", True), # Input flip_velocity
("Input_2_use_attribute", True), # Input flip_velocity
("Input_2_attribute_name", 'flip_velocity'), # Input flip_velocity
("Output_3_attribute_name", 'velocity'), # Output velocity
("Input_6", True), # Enable Motion Blur
("Input_6", True), # Enable Motion Blur
("Socket_7", bl_domain_object), # FLIP Domain Object
]
for (key, value) in key_value_pairs:
try:
# Input flip_velocity
gn_modifier[key] = value
except:
pass
@@ -231,21 +233,24 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
resource_filepath = os.path.join(parent_path, "resources", "geometry_nodes", blend_resource_filename)
gn_modifier = helper_operators.add_geometry_node_modifier(bl_cache_object, resource_filepath, "FF_GeometryNodesFluidParticles")
bl_domain_object = bpy.context.scene.flip_fluid.get_domain_object()
bl_surface_object = None
dprops = bpy.context.scene.flip_fluid.get_domain_properties()
if dprops is not None:
bl_surface_object = dprops.mesh_cache.surface.get_cache_object()
# Depending on FLIP Fluids version, the GN set up may not
# have these inputs. Available in FLIP Fluids 1.7.2 or later.
key_value_pairs = [
("Input_2_use_attribute", True), # Input flip_velocity
("Input_2_attribute_name", 'flip_velocity'), # Input flip_velocity
("Output_3_attribute_name", 'velocity'), # Output velocity
("Input_5", bl_cache_object.active_material), # Material
("Input_8", True), # Enable Motion Blur
("Input_9", True), # Enable Point Cloud
("Input_10", False), # Enable Instancing
("Socket_46", bl_domain_object), # FLIP Domain Object
("Socket_49", bl_surface_object), # FLIP Surface Object
]
for (key, value) in key_value_pairs:
try:
# Input flip_velocity
gn_modifier[key] = value
except:
pass
@@ -278,19 +283,25 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
resource_name = "FF_GeometryNodesWhitewaterSpray"
elif self.cache_object_type == 'CACHE_OBJECT_TYPE_DUST':
resource_name = "FF_GeometryNodesWhitewaterDust"
else:
return
gn_modifier = helper_operators.add_geometry_node_modifier(bl_cache_object, resource_filepath, resource_name)
bl_domain_object = bpy.context.scene.flip_fluid.get_domain_object()
bl_surface_object = None
dprops = bpy.context.scene.flip_fluid.get_domain_properties()
if dprops is not None:
bl_surface_object = dprops.mesh_cache.surface.get_cache_object()
# Depending on FLIP Fluids version, the GN set up may not
# have these inputs. Available in FLIP Fluids 1.7.2 or later.
key_value_pairs = [
("Input_2_use_attribute", True), # Input flip_velocity
("Input_2_attribute_name", 'flip_velocity'), # Input flip_velocity
("Output_3_attribute_name", 'velocity'), # Output velocity
("Input_5", bl_cache_object.active_material), # Material
("Input_8", True), # Enable Motion Blur
("Input_9", True), # Enable Point Cloud
("Input_10", False), # Enable Instancing
("Socket_29", bl_domain_object), # FLIP Domain Object
("Socket_32", bl_surface_object), # FLIP Surface Object
]
for (key, value) in key_value_pairs:
@@ -313,6 +324,90 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
self._set_cycles_use_motion_blur(bl_cache_object, True)
def _update_ff_geometry_nodes_modifier_domain_object(self, bl_cache_object):
if self.cache_object_type == 'CACHE_OBJECT_TYPE_SURFACE':
resource_name = "FF_GeometryNodesSurface"
socket_key = "Socket_7"
elif self.cache_object_type == 'CACHE_OBJECT_TYPE_FLUID_PARTICLES':
resource_name = "FF_GeometryNodesFluidParticles"
socket_key = "Socket_46"
elif self.cache_object_type == 'CACHE_OBJECT_TYPE_FOAM':
resource_name = "FF_GeometryNodesWhitewaterFoam"
socket_key = "Socket_29"
elif self.cache_object_type == 'CACHE_OBJECT_TYPE_BUBBLE':
resource_name = "FF_GeometryNodesWhitewaterBubble"
socket_key = "Socket_29"
elif self.cache_object_type == 'CACHE_OBJECT_TYPE_SPRAY':
resource_name = "FF_GeometryNodesWhitewaterSpray"
socket_key = "Socket_29"
elif self.cache_object_type == 'CACHE_OBJECT_TYPE_DUST':
resource_name = "FF_GeometryNodesWhitewaterDust"
socket_key = "Socket_29"
else:
return
bl_domain_object = bpy.context.scene.flip_fluid.get_domain_object()
if bl_domain_object is None:
return
gn_modifier = helper_operators.get_geometry_node_modifier(bl_cache_object, resource_name)
if gn_modifier is None:
return
try:
if gn_modifier[socket_key] != bl_domain_object:
gn_modifier[socket_key] = bl_domain_object
except:
pass
def _update_ff_geometry_nodes_modifier_fluid_surface_object(self, bl_cache_object):
if self.cache_object_type == 'CACHE_OBJECT_TYPE_SURFACE':
# Avoid circular dependency
return
if self.cache_object_type == 'CACHE_OBJECT_TYPE_FLUID_PARTICLES':
resource_name = "FF_GeometryNodesFluidParticles"
socket_key = "Socket_49"
elif self.cache_object_type == 'CACHE_OBJECT_TYPE_FOAM':
resource_name = "FF_GeometryNodesWhitewaterFoam"
socket_key = "Socket_32"
elif self.cache_object_type == 'CACHE_OBJECT_TYPE_BUBBLE':
resource_name = "FF_GeometryNodesWhitewaterBubble"
socket_key = "Socket_32"
elif self.cache_object_type == 'CACHE_OBJECT_TYPE_SPRAY':
resource_name = "FF_GeometryNodesWhitewaterSpray"
socket_key = "Socket_32"
elif self.cache_object_type == 'CACHE_OBJECT_TYPE_DUST':
resource_name = "FF_GeometryNodesWhitewaterDust"
socket_key = "Socket_32"
else:
return
dprops = bpy.context.scene.flip_fluid.get_domain_properties()
if dprops is None:
return
bl_surface_object = dprops.mesh_cache.surface.get_cache_object()
if bl_surface_object is None:
return
gn_modifier = helper_operators.get_geometry_node_modifier(bl_cache_object, resource_name)
if gn_modifier is None:
return
try:
if gn_modifier[socket_key] != bl_surface_object:
gn_modifier[socket_key] = bl_surface_object
except:
pass
def _update_ff_geometry_nodes_modifier(self, bl_cache_object):
self._update_ff_geometry_nodes_modifier_domain_object(bl_cache_object)
self._update_ff_geometry_nodes_modifier_fluid_surface_object(bl_cache_object)
def initialize_cache_object(self):
if not self._is_domain_set() or self._is_cache_object_initialized():
return
@@ -346,16 +441,16 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
self._initialize_cache_object_octane(cache_object)
if self.cache_object_type == 'CACHE_OBJECT_TYPE_SURFACE' and vcu.is_blender_31():
if self.cache_object_type == 'CACHE_OBJECT_TYPE_SURFACE':
self._initialize_cache_object_fluid_surface(cache_object)
if self.cache_object_type == 'CACHE_OBJECT_TYPE_FLUID_PARTICLES' and vcu.is_blender_31():
if self.cache_object_type == 'CACHE_OBJECT_TYPE_FLUID_PARTICLES':
self._initialize_cache_object_fluid_particles(cache_object)
if (self.cache_object_type == 'CACHE_OBJECT_TYPE_FOAM' or
self.cache_object_type == 'CACHE_OBJECT_TYPE_BUBBLE' or
self.cache_object_type == 'CACHE_OBJECT_TYPE_SPRAY' or
self.cache_object_type == 'CACHE_OBJECT_TYPE_DUST') and vcu.is_blender_31():
self.cache_object_type == 'CACHE_OBJECT_TYPE_DUST'):
self._initialize_cache_object_whitewater_particles(cache_object)
self.cache_object = cache_object
@@ -366,16 +461,16 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
if cache_object is None:
return
if self.cache_object_type == 'CACHE_OBJECT_TYPE_SURFACE' and vcu.is_blender_31():
if self.cache_object_type == 'CACHE_OBJECT_TYPE_SURFACE':
self._initialize_cache_object_fluid_surface(cache_object)
if self.cache_object_type == 'CACHE_OBJECT_TYPE_FLUID_PARTICLES' and vcu.is_blender_31():
if self.cache_object_type == 'CACHE_OBJECT_TYPE_FLUID_PARTICLES':
self._initialize_cache_object_fluid_particles(cache_object)
if (self.cache_object_type == 'CACHE_OBJECT_TYPE_FOAM' or
self.cache_object_type == 'CACHE_OBJECT_TYPE_BUBBLE' or
self.cache_object_type == 'CACHE_OBJECT_TYPE_SPRAY' or
self.cache_object_type == 'CACHE_OBJECT_TYPE_DUST') and vcu.is_blender_31():
self.cache_object_type == 'CACHE_OBJECT_TYPE_DUST'):
self._initialize_cache_object_whitewater_particles(cache_object)
self.cache_object = cache_object
@@ -404,34 +499,17 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
print(warning)
return
if vcu.is_blender_281():
mesh_data = cache_object.data
mesh_data = cache_object.data
is_smooth = self._is_mesh_smooth(mesh_data)
octane_mesh_type = self._get_octane_mesh_type(cache_object)
is_smooth = self._is_mesh_smooth(mesh_data)
octane_mesh_type = self._get_octane_mesh_type(cache_object)
vcu.swap_object_mesh_data_geometry(cache_object, [], [],
mesh_data,
is_smooth,
octane_mesh_type)
vcu.swap_object_mesh_data_geometry(cache_object, [], [],
mesh_data,
is_smooth,
octane_mesh_type)
self._set_mesh_smoothness(mesh_data, is_smooth)
self._set_octane_settings(cache_object, octane_mesh_type)
else:
old_mesh_data = cache_object.data
mesh_data_name = self.cache_object_default_name + "_mesh"
new_mesh_data = bpy.data.meshes.new(mesh_data_name)
new_mesh_data.from_pydata([], [], [])
self._transfer_mesh_materials(old_mesh_data, new_mesh_data)
self._transfer_mesh_smoothness(old_mesh_data, new_mesh_data)
self._transfer_octane_settings(cache_object, cache_object)
cache_object.data = new_mesh_data
vcu.delete_mesh_data(old_mesh_data)
self._set_mesh_smoothness(mesh_data, is_smooth)
self._set_octane_settings(cache_object, octane_mesh_type)
def _is_loaded_frame_up_to_date(self, frameno):
@@ -446,6 +524,7 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
self.enable_color_attribute != d.enable_color_attribute or
self.enable_source_id_attribute != d.enable_source_id_attribute or
self.enable_viscosity_attribute != d.enable_viscosity_attribute or
self.enable_density_attribute != d.enable_density_attribute or
self.enable_id_attribute != d.enable_id_attribute or
self.enable_uid_attribute != d.enable_uid_attribute or
self.enable_lifetime_attribute != d.enable_lifetime_attribute or
@@ -470,6 +549,7 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
d.enable_color_attribute = self.enable_color_attribute
d.enable_source_id_attribute = self.enable_source_id_attribute
d.enable_viscosity_attribute = self.enable_viscosity_attribute
d.enable_density_attribute = self.enable_density_attribute
d.enable_id_attribute = self.enable_id_attribute
d.enable_uid_attribute = self.enable_uid_attribute
d.enable_lifetime_attribute = self.enable_lifetime_attribute
@@ -509,7 +589,7 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
frame_string = self._frame_number_to_string(frameno)
current_frame = render.get_current_render_frame()
if vcu.is_blender_281() and cache_object.data.shape_keys is not None:
if cache_object.data.shape_keys is not None:
for idx,key in enumerate(cache_object.data.shape_keys.key_blocks):
cache_object.shape_key_remove(key=key)
@@ -538,7 +618,7 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
def _update_velocity_attribute(self, frameno):
if not vcu.is_blender_293() or not self.enable_velocity_attribute:
if not self.enable_velocity_attribute:
return
cache_object = self.get_cache_object()
@@ -560,7 +640,7 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
def _update_speed_attribute(self, frameno):
if not vcu.is_blender_293() or not self.enable_speed_attribute:
if not self.enable_speed_attribute:
return
cache_object = self.get_cache_object()
@@ -582,7 +662,7 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
def _update_vorticity_attribute(self, frameno):
if not vcu.is_blender_293() or not self.enable_vorticity_attribute:
if not self.enable_vorticity_attribute:
return
cache_object = self.get_cache_object()
@@ -604,7 +684,7 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
def _update_age_attribute(self, frameno):
if not vcu.is_blender_293() or not self.enable_age_attribute:
if not self.enable_age_attribute:
return
cache_object = self.get_cache_object()
@@ -626,7 +706,7 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
def _update_color_attribute(self, frameno):
if not vcu.is_blender_293() or not self.enable_color_attribute:
if not self.enable_color_attribute:
return
cache_object = self.get_cache_object()
@@ -648,7 +728,7 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
def _update_source_id_attribute(self, frameno):
if not vcu.is_blender_293() or not self.enable_source_id_attribute:
if not self.enable_source_id_attribute:
return
cache_object = self.get_cache_object()
@@ -670,7 +750,7 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
def _update_uid_attribute(self, frameno):
if not vcu.is_blender_293() or not self.enable_uid_attribute:
if not self.enable_uid_attribute:
return
cache_object = self.get_cache_object()
@@ -692,7 +772,7 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
def _update_viscosity_attribute(self, frameno):
if not vcu.is_blender_293() or not self.enable_viscosity_attribute:
if not self.enable_viscosity_attribute:
return
cache_object = self.get_cache_object()
@@ -713,8 +793,47 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
attribute.data.foreach_set("value", viscosity_data)
def _update_density_attribute(self, frameno):
if not self.enable_density_attribute:
return
cache_object = self.get_cache_object()
frame_string = self._frame_number_to_string(frameno)
density_data, _ = self._import_density_attribute_data(frameno)
if not density_data:
return
attribute_name = "flip_density"
mesh = cache_object.data
try:
mesh.attributes.remove(mesh.attributes.get(attribute_name))
except:
pass
attribute = mesh.attributes.new(attribute_name, "FLOAT", "POINT")
attribute.data.foreach_set("value", density_data)
# flip_density_average attribute needs more work
"""
density_average_data, _ = self._import_density_average_attribute_data(frameno)
if not density_average_data:
return
attribute_name = "flip_density_average"
mesh = cache_object.data
try:
mesh.attributes.remove(mesh.attributes.get(attribute_name))
except:
pass
attribute = mesh.attributes.new(attribute_name, "FLOAT", "POINT")
attribute.data.foreach_set("value", density_average_data)
"""
def _update_id_attribute(self, frameno):
if not vcu.is_blender_293() or not self.enable_id_attribute:
if not self.enable_id_attribute:
return
cache_object = self.get_cache_object()
@@ -768,7 +887,7 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
def _update_lifetime_attribute(self, frameno):
if not vcu.is_blender_293() or not self.enable_lifetime_attribute:
if not self.enable_lifetime_attribute:
return
cache_object = self.get_cache_object()
@@ -790,7 +909,7 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
def _update_whitewater_proximity_attribute(self, frameno):
if not vcu.is_blender_293() or not self.enable_whitewater_proximity_attribute:
if not self.enable_whitewater_proximity_attribute:
return
cache_object = self.get_cache_object()
@@ -833,9 +952,6 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
# Cache values unrelated to geometry will be stored on the domain vertices
# to minimize memory usage
def _update_domain_data_storage_attributes(self, current_frame):
if not vcu.is_blender_293():
return
domain_object = self._get_domain_object()
if not domain_object:
return
@@ -879,6 +995,42 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
attribute = mesh.attributes.new(attribute_name, "INT", "POINT")
attribute.data.foreach_set("value", [max_uid_value] * len(attribute.data))
# Store per frame metadata values
bakefiles_directory = self._get_bakefiles_directory()
metadata_filename = "metadata" + self._frame_number_to_string(current_frame) + ".json"
metadata_filepath = os.path.join(bakefiles_directory, metadata_filename)
metadata_dict = {}
if os.path.isfile(metadata_filepath):
with open(metadata_filepath, "r") as metadata_file:
metadata_dict = json.load(metadata_file)
time_scale_value = 1.0
if 'time_scale' in metadata_dict:
time_scale_value = metadata_dict['time_scale']
world_scale_value = 1.0
if 'world_scale' in metadata_dict:
world_scale_value = metadata_dict['world_scale']
attribute_list = [
("flip_time_scale", "FLOAT", time_scale_value),
("flip_world_scale", "FLOAT", world_scale_value),
]
for attribute_data in attribute_list:
attribute_name = attribute_data[0]
attribute_type = attribute_data[1]
attribute_value = attribute_data[2]
mesh = domain_object.data
try:
mesh.attributes.remove(mesh.attributes.get(attribute_name))
except:
pass
attribute = mesh.attributes.new(attribute_name, attribute_type, "POINT")
attribute.data.foreach_set("value", [attribute_value] * len(attribute.data))
def load_frame(self, frameno, force_load=False, depsgraph=None):
if not self._is_load_frame_valid(frameno, force_load):
@@ -912,6 +1064,7 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
octane_mesh_type)
self.update_transforms()
self._update_ff_geometry_nodes_modifier(cache_object)
self._update_motion_blur(frameno)
self._update_velocity_attribute(frameno)
self._update_speed_attribute(frameno)
@@ -920,6 +1073,7 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
self._update_color_attribute(frameno)
self._update_source_id_attribute(frameno)
self._update_viscosity_attribute(frameno)
self._update_density_attribute(frameno)
self._update_id_attribute(frameno)
self._update_uid_attribute(frameno)
self._update_lifetime_attribute(frameno)
@@ -929,18 +1083,6 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
self.current_loaded_frame = render.get_current_render_frame()
self._commit_loaded_frame_data(frameno)
if vcu.is_blender_279() or render.is_rendering():
use_persistent_data = bpy.context.scene.render.use_persistent_data
is_keyframed_hide_render = render.is_keyframed_hide_render_issue_relevant()
if not use_persistent_data and not is_keyframed_hide_render:
# Updating depsgraph when 'Persistent Data' option is enabled
# causes incorrect render. Note: ignoring the depsgraph update
# can result in more frequent render crashes.
if depsgraph is not None:
depsgraph.update()
else:
vcu.depsgraph_update()
def update_transforms(self):
cache_object = self.get_cache_object()
@@ -982,11 +1124,7 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
if self.cache_object is None:
return None
if vcu.is_blender_28():
object_collection = bpy.context.scene.collection.all_objects
else:
object_collection = bpy.context.scene.objects
object_collection = bpy.context.scene.collection.all_objects
if object_collection.get(self.cache_object.name) is None:
self.delete_cache_object()
return self.cache_object
@@ -1388,6 +1526,30 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
return os.path.join(bakefiles_directory, filename)
def _get_density_attribute_filepath(self, frameno):
filename = ("density" + self.mesh_prefix +
self._frame_number_to_string(frameno) +
".data")
bakefiles_directory = self._get_bakefiles_directory()
return os.path.join(bakefiles_directory, filename)
def _get_fluid_particle_density_attribute_filepath(self, frameno):
filename = (self.mesh_prefix + "density" +
self._frame_number_to_string(frameno) +
".ffp3")
bakefiles_directory = self._get_bakefiles_directory()
return os.path.join(bakefiles_directory, filename)
def _get_fluid_particle_density_average_attribute_filepath(self, frameno):
filename = (self.mesh_prefix + "densityaverage" +
self._frame_number_to_string(frameno) +
".ffp3")
bakefiles_directory = self._get_bakefiles_directory()
return os.path.join(bakefiles_directory, filename)
def _get_id_attribute_filepath(self, frameno):
filename = ("id" + self.mesh_prefix +
self._frame_number_to_string(frameno) +
@@ -1460,11 +1622,7 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
if self.cache_object is None:
return False
if vcu.is_blender_28():
object_collection = bpy.context.scene.collection.all_objects
else:
object_collection = bpy.context.scene.objects
object_collection = bpy.context.scene.collection.all_objects
if object_collection.get(self.cache_object.name) is None:
self.delete_cache_object()
return False
@@ -1819,6 +1977,62 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
return viscosity_data, header_info
def _import_density_attribute_data(self, frameno):
header_info = None
density_data = []
if not self._is_domain_set() or not self._is_frame_cached(frameno):
return density_data, header_info
if self.cache_object_type == 'CACHE_OBJECT_TYPE_FLUID_PARTICLES':
filepath = self._get_fluid_particle_density_attribute_filepath(frameno)
else:
filepath = self._get_density_attribute_filepath(frameno)
if not os.path.exists(filepath):
return density_data, header_info
import_function = getattr(self, self.import_function_name)
if import_function == self.import_wwp:
density_data, _ = import_function(filepath, self.wwp_import_percentage)
elif import_function == self.import_ffp3:
density_data, _, header_info = self.import_ffp3(
filepath,
pct_surface=self.ffp3_surface_import_percentage,
pct_boundary=self.ffp3_boundary_import_percentage,
pct_interior=self.ffp3_interior_import_percentage,
attribute_type='ATTRIBUTE_TYPE_FLOAT'
)
else:
density_data = self.import_floats(filepath)
return density_data, header_info
def _import_density_average_attribute_data(self, frameno):
header_info = None
density_average_data = []
if not self._is_domain_set() or not self._is_frame_cached(frameno):
return density_average_data, header_info
if self.cache_object_type != 'CACHE_OBJECT_TYPE_FLUID_PARTICLES':
# Attribute only available for fluid particles
return density_average_data, header_info
filepath = self._get_fluid_particle_density_average_attribute_filepath(frameno)
if not os.path.exists(filepath):
return density_average_data, header_info
density_average_data, _, header_info = self.import_ffp3(
filepath,
pct_surface=self.ffp3_surface_import_percentage,
pct_boundary=self.ffp3_boundary_import_percentage,
pct_interior=self.ffp3_interior_import_percentage,
attribute_type='ATTRIBUTE_TYPE_FLOAT'
)
return density_average_data, header_info
def _import_id_attribute_data(self, frameno):
header_info = None
id_data = []
@@ -1933,12 +2147,11 @@ class FlipFluidMeshCache(bpy.types.PropertyGroup):
class FlipFluidGLPointCache(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
mesh_prefix = StringProperty(default=""); exec(conv("mesh_prefix"))
mesh_file_extension = StringProperty(default=""); exec(conv("mesh_file_extension"))
current_loaded_frame = IntProperty(default=-1); exec(conv("current_loaded_frame"))
uid = IntProperty(default=-1); exec(conv("uid"))
is_enabled = BoolProperty(default=False); exec(conv("is_enabled"))
mesh_prefix: StringProperty(default="")
mesh_file_extension: StringProperty(default="")
current_loaded_frame: IntProperty(default=-1)
uid: IntProperty(default=-1)
is_enabled: BoolProperty(default=False)
def enable(self):
@@ -2084,12 +2297,11 @@ class FlipFluidGLPointCache(bpy.types.PropertyGroup):
class FlipFluidGLForceFieldCache(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
mesh_prefix = StringProperty(default=""); exec(conv("mesh_prefix"))
mesh_file_extension = StringProperty(default=""); exec(conv("mesh_file_extension"))
current_loaded_frame = IntProperty(default=-1); exec(conv("current_loaded_frame"))
uid = IntProperty(default=-1); exec(conv("uid"))
is_enabled = BoolProperty(default=False); exec(conv("is_enabled"))
mesh_prefix: StringProperty(default="")
mesh_file_extension: StringProperty(default="")
current_loaded_frame: IntProperty(default=-1)
uid: IntProperty(default=-1)
is_enabled: BoolProperty(default=False)
def enable(self):
@@ -2221,16 +2433,15 @@ class FlipFluidGLForceFieldCache(bpy.types.PropertyGroup):
class FlipFluidCache(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
surface = PointerProperty(type=FlipFluidMeshCache); exec(conv("surface"))
particles = PointerProperty(type=FlipFluidMeshCache); exec(conv("particles"))
foam = PointerProperty(type=FlipFluidMeshCache); exec(conv("foam"))
bubble = PointerProperty(type=FlipFluidMeshCache); exec(conv("bubble"))
spray = PointerProperty(type=FlipFluidMeshCache); exec(conv("spray"))
dust = PointerProperty(type=FlipFluidMeshCache); exec(conv("dust"))
gl_particles = PointerProperty(type=FlipFluidGLPointCache); exec(conv("gl_particles"))
gl_force_field = PointerProperty(type=FlipFluidGLForceFieldCache); exec(conv("gl_force_field"))
obstacle = PointerProperty(type=FlipFluidMeshCache); exec(conv("obstacle"))
surface: PointerProperty(type=FlipFluidMeshCache)
particles: PointerProperty(type=FlipFluidMeshCache)
foam: PointerProperty(type=FlipFluidMeshCache)
bubble: PointerProperty(type=FlipFluidMeshCache)
spray: PointerProperty(type=FlipFluidMeshCache)
dust: PointerProperty(type=FlipFluidMeshCache)
gl_particles: PointerProperty(type=FlipFluidGLPointCache)
gl_force_field: PointerProperty(type=FlipFluidGLForceFieldCache)
obstacle: PointerProperty(type=FlipFluidMeshCache)
def initialize_cache_settings(self):
@@ -29,7 +29,7 @@ from ..utils import cache_utils
def find_fcurve(id_data, path, index=0):
anim_data = id_data.animation_data
for fcurve in anim_data.action.fcurves:
for fcurve in anim_data.action.layers[0].strips[0].channelbag(anim_data.action.slots[0]).fcurves:
if fcurve.data_path == path and fcurve.array_index == index:
return fcurve
@@ -81,6 +81,32 @@ def get_rotation_mode_at_frame(obj, frame_id):
return mode
def get_delta_transforms_at_frame(obj, frame_id):
rotation_mode = get_rotation_mode_at_frame(obj, frame_id)
if rotation_mode == 'AXIS_ANGLE':
# No delta rotation for AXIS_ANGLE mode
rotation_matrix = Matrix.Identity(4)
elif rotation_mode == 'QUATERNION':
rotation_quat = get_vector4_at_frame(obj, "delta_rotation_quaternion", frame_id)
quaternion = Quaternion(rotation_quat)
rotation_matrix = quaternion.to_euler().to_matrix().to_4x4()
else:
rotation = get_vector3_at_frame(obj, "delta_rotation_euler", frame_id)
euler_rotation = Euler(rotation, rotation_mode)
rotation_matrix = euler_rotation.to_matrix().to_4x4()
location = get_vector3_at_frame(obj, "delta_location", frame_id)
location_matrix = Matrix.Translation(location).to_4x4()
scale = get_vector3_at_frame(obj, "delta_scale", frame_id)
scale_matrix = Matrix.Identity(4)
scale_matrix[0][0] = scale[0]
scale_matrix[1][1] = scale[1]
scale_matrix[2][2] = scale[2]
return location_matrix, rotation_matrix, scale_matrix
def get_matrix_world_at_frame(obj, frame_id):
rotation_mode = get_rotation_mode_at_frame(obj, frame_id)
if rotation_mode == 'AXIS_ANGLE':
@@ -105,8 +131,13 @@ def get_matrix_world_at_frame(obj, frame_id):
scale_matrix[0][0] = scale[0]
scale_matrix[1][1] = scale[1]
scale_matrix[2][2] = scale[2]
delta_location_matrix, delta_rotation_matrix, delta_scale_matrix = get_delta_transforms_at_frame(obj, frame_id)
total_location_matrix = delta_location_matrix @ location_matrix
total_rotation_matrix = delta_rotation_matrix @ rotation_matrix
total_scale_matrix = delta_scale_matrix @ scale_matrix
return vcu.element_multiply(vcu.element_multiply(location_matrix, rotation_matrix), scale_matrix)
return vcu.element_multiply(vcu.element_multiply(total_location_matrix, total_rotation_matrix), total_scale_matrix)
def get_mesh_centroid(obj, apply_transforms=True):
@@ -30,13 +30,12 @@ from ..utils import version_compatibility_utils as vcu
class FLIPFluidMaterialLibraryMaterial(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
name = StringProperty(default=""); exec(conv("name"))
description = StringProperty(default=""); exec(conv("description"))
path = StringProperty(default=""); exec(conv("path"))
type = EnumProperty(items=types.material_types, default="MATERIAL_TYPE_SURFACE"); exec(conv("type"))
icon_id = IntProperty(default=-1); exec(conv("icon_id"))
imported_icon_id = IntProperty(default=-1); exec(conv("imported_icon_id"))
name: StringProperty(default="")
description: StringProperty(default="")
path: StringProperty(default="")
type: EnumProperty(items=types.material_types, default="MATERIAL_TYPE_SURFACE")
icon_id: IntProperty(default=-1)
imported_icon_id: IntProperty(default=-1)
def get_ui_enum(self):
@@ -60,9 +59,8 @@ class FLIPFluidMaterialLibraryMaterial(bpy.types.PropertyGroup):
class FLIPFluidMaterialLibrary(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
library_path = StringProperty(default=""); exec(conv("library_path"))
material_list = CollectionProperty(type=FLIPFluidMaterialLibraryMaterial); exec(conv("material_list"))
library_path: StringProperty(default="")
material_list: CollectionProperty(type=FLIPFluidMaterialLibraryMaterial)
@classmethod
@@ -29,10 +29,9 @@ from ..utils import version_compatibility_utils as vcu
class PresetStackProperty(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
path = StringProperty(); exec(conv("path"))
value = StringProperty(); exec(conv("value"))
is_value_set = BoolProperty(default=False); exec(conv("is_value_set"))
path: StringProperty()
value: StringProperty()
is_value_set: BoolProperty(default=False)
def get_value(self):
@@ -51,27 +50,25 @@ class PresetStackProperty(bpy.types.PropertyGroup):
class PresetStackMaterialInfo(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
preset_id = StringProperty(); exec(conv("preset_id"))
loaded_id = StringProperty(); exec(conv("loaded_id"))
preset_id: StringProperty()
loaded_id: StringProperty()
class PresetStackElement(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
is_enabled = BoolProperty(
is_enabled: BoolProperty(
name="Enabled",
description="Enable effects of preset in the stack",
default=True,
update=lambda self, context: self._update_is_enabled(context),
); exec(conv("is_enabled"))
)
is_applied = BoolProperty(default=False); exec(conv("is_applied"))
is_active = BoolProperty(default=True); exec(conv("is_active"))
identifier = StringProperty(); exec(conv("identifier"))
stack_uid = IntProperty(default=-1); exec(conv("stack_uid"))
saved_properties = CollectionProperty(type=PresetStackProperty); exec(conv("saved_properties"))
loaded_materials = CollectionProperty(type=PresetStackMaterialInfo); exec(conv("loaded_materials"))
is_applied: BoolProperty(default=False)
is_active: BoolProperty(default=True)
identifier: StringProperty()
stack_uid: IntProperty(default=-1)
saved_properties: CollectionProperty(type=PresetStackProperty)
loaded_materials: CollectionProperty(type=PresetStackMaterialInfo)
def clear(self):
@@ -165,11 +162,10 @@ class PresetStackElement(bpy.types.PropertyGroup):
class FlipFluidPresetStack(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
is_enabled = BoolProperty(default=False); exec(conv("is_enabled"))
staged_preset = PointerProperty(type=PresetStackElement); exec(conv("staged_preset"))
is_preset_staged = BoolProperty(default=False); exec(conv("is_preset_staged"))
preset_stack = CollectionProperty(type=PresetStackElement); exec(conv("preset_stack"))
is_enabled: BoolProperty(default=False)
staged_preset: PointerProperty(type=PresetStackElement)
is_preset_staged: BoolProperty(default=False)
preset_stack: CollectionProperty(type=PresetStackElement)
def enable(self):
@@ -205,7 +205,12 @@ class FlipFluidAddQuickLiquid(bpy.types.Operator):
# Domain Settings
domain_properties = bpy.context.scene.flip_fluid.get_domain_properties()
domain_properties.materials.surface_material = 'FF Water (ocean volumetric)'
try:
# Materials may not be available depending on addon version
domain_properties.materials.surface_material = 'FF Water (ocean volumetric)'
except:
pass
# Surface Settings
domain_properties = bpy.context.scene.flip_fluid.get_domain_properties()
@@ -282,9 +287,14 @@ class FlipFluidAddThickViscousLiquid(bpy.types.Operator):
domain_props.surface.subdivisions = 2
domain_props.world.enable_viscosity = True
domain_props.world.viscosity = 15
domain_props.materials.surface_material = 'FF Caramel'
domain_props.advanced.jitter_surface_particles = True
try:
# Materials may not be available depending on addon version
domain_props.materials.surface_material = 'FF Caramel'
except:
pass
# Create Inflow
bpy.ops.mesh.primitive_cylinder_add(radius=0.25, location=(-0.125, -0.125, 1.25 + z_offset), scale=(0.4, 0.4, 0.25))
bl_cylinder = bpy.context.active_object
@@ -402,9 +412,14 @@ class FlipFluidAddThinViscousLiquid(bpy.types.Operator):
domain_props.world.surface_tension_settings_expaned = True
domain_props.world.enable_surface_tension = True
domain_props.world.surface_tension = 0.3
domain_props.materials.surface_material = 'FF Caramel'
domain_props.advanced.jitter_surface_particles = True
try:
# Materials may not be available depending on addon version
domain_props.materials.surface_material = 'FF Caramel'
except:
pass
# Create Inflow
bpy.ops.mesh.primitive_cylinder_add(radius=0.25, location=(-0.5, -0.5, 0.0 + z_offset), scale=(0.4, 0.4, 0.125))
bl_cylinder = bpy.context.active_object
@@ -39,47 +39,42 @@ class FLIPFluidsAlembicImporter(bpy.types.Operator, bpy_extras.io_utils.ImportHe
return bl_object
def apply_default_modifier_settings(self, target_object, gn_modifier):
gn_modifier["Input_2_use_attribute"] = True
gn_modifier["Input_2_attribute_name"] = 'flip_velocity'
gn_modifier["Output_3_attribute_name"] = 'velocity'
def apply_default_modifier_settings(self, target_object, domain_object, surface_object, gn_modifier):
# Apply Simulation Time Scale and Apply Simulation Time Scale should be disabled.
# These modifier features require a FLIP Domain and addon scripting to function. If enabled,
# motion blur velocity will be set to (0.0, 0.0, 0.0)
key_value_pairs_surface = [
("Input_6", True), # Enable Motion Blur
("Socket_8", False), # Apply Simulation Time Scale - Disable: Requires FLIP Domain and addon scripting
("Socket_9", False), # Apply Simulation Time Scale - Disable: Requires FLIP Domain and addon scripting
("Socket_7", domain_object), # FLIP Domain Object
]
key_value_pairs_particles = [
("Input_8", True), # Enable Motion Blur
("Socket_47", False), # Apply Simulation Time Scale - Disable: Requires FLIP Domain and addon scripting
("Socket_48", False), # Apply Simulation World Scale - Disable: Requires FLIP Domain and addon scripting
("Socket_46", domain_object), # FLIP Domain Object
("Socket_49", surface_object), # FLIP Surface Object
]
# Depending on FLIP Fluids version, the GN set up may not
# have these inputs.
gn_name = gn_modifier.name
if gn_name.startswith("FF_GeometryNodesSurface"):
# Depending on FLIP Fluids version, the GN set up may not
# have these inputs. Available in FLIP Fluids 1.7.2 or later.
try:
# Enable Motion Blur
gn_modifier["Input_6"] = True
except:
pass
if gn_name.startswith("FF_GeometryNodesAlembicSurface"):
for (key, value) in key_value_pairs_surface:
try:
gn_modifier[key] = value
except:
pass
if gn_name.startswith("FF_GeometryNodesWhitewater") or gn_name.startswith("FF_GeometryNodesFluidParticles"):
# Depending on FLIP Fluids version, the GN set up may not
# have these inputs. Available in FLIP Fluids 1.7.2 or later.
try:
# Material
gn_modifier["Input_5"] = target_object.active_material
except:
pass
try:
# Enable Motion Blur
gn_modifier["Input_8"] = True
except:
pass
try:
# Enable Point Cloud
gn_modifier["Input_9"] = True
except:
pass
try:
# Enable Instancing
gn_modifier["Input_10"] = False
except:
pass
if gn_name.startswith("FF_GeometryNodesAlembicParticles"):
for (key, value) in key_value_pairs_particles:
try:
gn_modifier[key] = value
except:
pass
def add_smooth_modifier(self, target_object):
@@ -89,11 +84,25 @@ class FLIPFluidsAlembicImporter(bpy.types.Operator, bpy_extras.io_utils.ImportHe
return smooth_mod
def toggle_cycles_ray_visibility(self, obj, is_enabled):
# Cycles may not be enabled in the user's preferences
try:
obj.visible_camera = is_enabled
obj.visible_diffuse = is_enabled
obj.visible_glossy = is_enabled
obj.visible_transmission = is_enabled
obj.visible_volume_scatter = is_enabled
obj.visible_shadow = is_enabled
except:
pass
def execute(self, context):
print("FLIP Fluids Alembic Import: <" + self.filepath + ">")
bpy.ops.wm.alembic_import(filepath=self.filepath)
bpy.ops.wm.alembic_import(filepath=self.filepath, always_add_cache_reader=True)
bl_domain = self.find_flip_fluids_mesh(bpy.context.selected_objects, "FLIP_Domain")
bl_fluid_surface = self.find_flip_fluids_mesh(bpy.context.selected_objects, "fluid_surface")
bl_fluid_particles = self.find_flip_fluids_mesh(bpy.context.selected_objects, "fluid_particles")
bl_whitewater_foam = self.find_flip_fluids_mesh(bpy.context.selected_objects, "whitewater_foam")
@@ -107,46 +116,51 @@ class FLIPFluidsAlembicImporter(bpy.types.Operator, bpy_extras.io_utils.ImportHe
found_mesh_cache_list = []
if bl_domain is not None:
bl_domain.hide_render = True
bl_domain.display_type = 'BOUNDS'
self.toggle_cycles_ray_visibility(bl_domain, False)
if bl_fluid_surface is not None:
self.add_smooth_modifier(bl_fluid_surface)
helper_operators.add_geometry_node_modifier(bl_fluid_surface, resource_filepath, "FF_AlembicImportSurface")
gn_modifier = helper_operators.add_geometry_node_modifier(bl_fluid_surface, resource_filepath, "FF_GeometryNodesSurface")
self.apply_default_modifier_settings(bl_fluid_surface, gn_modifier)
gn_modifier = helper_operators.add_geometry_node_modifier(bl_fluid_surface, resource_filepath, "FF_GeometryNodesAlembicSurface")
self.apply_default_modifier_settings(bl_fluid_surface, bl_domain, bl_fluid_surface, gn_modifier)
self.report({'INFO'}, "Found fluid surface cache... Initialized geometry nodes")
found_mesh_cache_list.append("Surface")
if bl_fluid_particles is not None:
helper_operators.add_geometry_node_modifier(bl_fluid_particles, resource_filepath, "FF_AlembicImportFluidParticles")
gn_modifier = helper_operators.add_geometry_node_modifier(bl_fluid_particles, resource_filepath, "FF_GeometryNodesFluidParticles")
self.apply_default_modifier_settings(bl_fluid_particles, gn_modifier)
gn_modifier = helper_operators.add_geometry_node_modifier(bl_fluid_particles, resource_filepath, "FF_GeometryNodesAlembicParticles")
self.apply_default_modifier_settings(bl_fluid_particles, bl_domain, bl_fluid_surface, gn_modifier)
self.report({'INFO'}, "Found fluid particle cache... Initialized geometry nodes")
found_mesh_cache_list.append("FluidParticles")
if bl_whitewater_foam is not None:
helper_operators.add_geometry_node_modifier(bl_whitewater_foam, resource_filepath, "FF_AlembicImportWhitewaterFoam")
gn_modifier = helper_operators.add_geometry_node_modifier(bl_whitewater_foam, resource_filepath, "FF_GeometryNodesWhitewaterFoam")
self.apply_default_modifier_settings(bl_whitewater_foam, gn_modifier)
gn_modifier = helper_operators.add_geometry_node_modifier(bl_whitewater_foam, resource_filepath, "FF_GeometryNodesAlembicParticles")
self.apply_default_modifier_settings(bl_whitewater_foam, bl_domain, bl_fluid_surface, gn_modifier)
self.report({'INFO'}, "Found whitewater foam cache... Initialized geometry nodes")
found_mesh_cache_list.append("Foam")
if bl_whitewater_bubble is not None:
helper_operators.add_geometry_node_modifier(bl_whitewater_bubble, resource_filepath, "FF_AlembicImportWhitewaterBubble")
gn_modifier = helper_operators.add_geometry_node_modifier(bl_whitewater_bubble, resource_filepath, "FF_GeometryNodesWhitewaterBubble")
self.apply_default_modifier_settings(bl_whitewater_bubble, gn_modifier)
gn_modifier = helper_operators.add_geometry_node_modifier(bl_whitewater_bubble, resource_filepath, "FF_GeometryNodesAlembicParticles")
self.apply_default_modifier_settings(bl_whitewater_bubble, bl_domain, bl_fluid_surface, gn_modifier)
self.report({'INFO'}, "Found whitewater bubble cache... Initialized geometry nodes")
found_mesh_cache_list.append("Bubble")
if bl_whitewater_spray is not None:
helper_operators.add_geometry_node_modifier(bl_whitewater_spray, resource_filepath, "FF_AlembicImportWhitewaterSpray")
gn_modifier = helper_operators.add_geometry_node_modifier(bl_whitewater_spray, resource_filepath, "FF_GeometryNodesWhitewaterSpray")
self.apply_default_modifier_settings(bl_whitewater_spray, gn_modifier)
gn_modifier = helper_operators.add_geometry_node_modifier(bl_whitewater_spray, resource_filepath, "FF_GeometryNodesAlembicParticles")
self.apply_default_modifier_settings(bl_whitewater_spray, bl_domain, bl_fluid_surface, gn_modifier)
self.report({'INFO'}, "Found whitewater spray cache... Initialized geometry nodes")
found_mesh_cache_list.append("Spray")
if bl_whitewater_dust is not None:
helper_operators.add_geometry_node_modifier(bl_whitewater_dust, resource_filepath, "FF_AlembicImportWhitewaterDust")
gn_modifier = helper_operators.add_geometry_node_modifier(bl_whitewater_dust, resource_filepath, "FF_GeometryNodesWhitewaterDust")
self.apply_default_modifier_settings(bl_whitewater_dust, gn_modifier)
gn_modifier = helper_operators.add_geometry_node_modifier(bl_whitewater_dust, resource_filepath, "FF_GeometryNodesAlembicParticles")
self.apply_default_modifier_settings(bl_whitewater_dust, bl_domain, bl_fluid_surface, gn_modifier)
self.report({'INFO'}, "Found whitewater dust cache... Initialized geometry nodes")
found_mesh_cache_list.append("Dust")
@@ -177,12 +191,17 @@ class FLIPFluidsAlembicExporter(bpy.types.Operator, bpy_extras.io_utils.ExportHe
return context.scene.flip_fluid.get_domain_object() is not None and bool(bpy.data.filepath)
def draw(self, context):
def draw_alembic_export_engine_blender(self, context):
hprops = context.scene.flip_fluid_helper
self.layout.use_property_split = True
self.layout.use_property_decorate = False
header, body = self.layout.panel("alembic_export_engine", default_closed=False)
header.label(text="Alembic Exporter")
if body:
column = body.column(align=True)
column.prop(hprops, "alembic_export_engine", text="Engine")
header, body = self.layout.panel("alembic_scene", default_closed=False)
header.label(text="Scene")
if body:
@@ -217,16 +236,116 @@ class FLIPFluidsAlembicExporter(bpy.types.Operator, bpy_extras.io_utils.ExportHe
header, body = self.layout.panel("alembic_command", default_closed=True)
header.label(text="Command")
if body:
column = body.column(heading="Attributes", align=True)
hprops = context.scene.flip_fluid_helper
column = body.column(heading="Command", align=True)
column.operator("flip_fluid_operators.helper_cmd_alembic_export_to_clipboard", text="Copy Command to Clipboard", icon='COPYDOWN')
def draw_alembic_export_engine_flip_fluids(self, context):
hprops = context.scene.flip_fluid_helper
self.layout.use_property_split = True
self.layout.use_property_decorate = False
header, body = self.layout.panel("alembic_export_engine", default_closed=False)
header.label(text="Alembic Exporter")
if body:
column = body.column(align=True)
column.prop(hprops, "alembic_export_engine", text="Engine")
header, body = self.layout.panel("alembic_scene", default_closed=False)
header.label(text="Scene")
if body:
column = body.column(align=True)
column.prop(hprops, "alembic_frame_range_mode", text="Frame Range")
if hprops.alembic_frame_range_mode == 'FRAME_RANGE_TIMELINE':
column.prop(context.scene, "frame_start")
column.prop(context.scene, "frame_end")
else:
column.prop(hprops.alembic_frame_range_custom, "value_min")
column.prop(hprops.alembic_frame_range_custom, "value_max")
column.separator()
column.prop(hprops, "alembic_global_scale", text="Scale (TODO)")
header, body = self.layout.panel("alembic_include", default_closed=False)
header.label(text="Include")
if body:
column = body.column(heading="Mesh", align=True)
column.prop(hprops, "alembic_export_surface")
column.prop(hprops, "alembic_export_surface_preview", text="Surface Preview (TODO)")
column.prop(hprops, "alembic_export_fluid_particles", text="Fluid Particles (TODO)")
column.prop(hprops, "alembic_export_foam", text="Foam (TODO)")
column.prop(hprops, "alembic_export_bubble", text="Bubble (TODO)")
column.prop(hprops, "alembic_export_spray", text="Spray (TODO)")
column.prop(hprops, "alembic_export_dust", text="Dust (TODO)")
column = body.column(heading="Attributes", align=True)
column.prop(hprops, "alembic_export_velocity", text="Velocity (TODO)")
column.prop(hprops, "alembic_export_color", text="Color (TODO)")
header, body = self.layout.panel("alembic_command", default_closed=True)
header.label(text="Command")
if body:
hprops = context.scene.flip_fluid_helper
column = body.column(heading="Command", align=True)
column.enabled = False
column.operator("flip_fluid_operators.cmd_custom_alembic_export_to_clipboard", text="Copy Command to Clipboard (TODO)", icon='COPYDOWN')
def draw(self, context):
hprops = context.scene.flip_fluid_helper
if hprops.alembic_export_engine == 'ALEMBIC_EXPORT_ENGINE_FLIP_FLUIDS':
self.draw_alembic_export_engine_flip_fluids(context)
elif hprops.alembic_export_engine == 'ALEMBIC_EXPORT_ENGINE_BLENDER':
self.draw_alembic_export_engine_blender(context)
def alembic_export_engine_flip_fluids(self):
hprops = bpy.context.scene.flip_fluid_helper
hprops.alembic_output_filepath = self.filepath
bpy.ops.flip_fluid_operators.helper_cmd_custom_alembic_export('INVOKE_DEFAULT')
def alembic_export_engine_blender(self):
hprops = bpy.context.scene.flip_fluid_helper
hprops.alembic_output_filepath = self.filepath
bpy.ops.flip_fluid_operators.helper_command_line_alembic_export('INVOKE_DEFAULT')
def check_cache_exists(self, context):
dprops = context.scene.flip_fluid.get_domain_properties()
cache_directory = dprops.cache.get_cache_abspath()
bakefiles_directory = os.path.join(cache_directory, "bakefiles")
file_count = 0
cache_exists = False
if os.path.isdir(bakefiles_directory):
cache_exists = True
file_count = len(os.listdir(bakefiles_directory))
if not cache_exists or file_count == 0:
return False
return True
def execute(self, context):
if not self.check_cache_exists(context):
dprops = context.scene.flip_fluid.get_domain_properties()
cache_directory = dprops.cache.get_cache_abspath()
self.report({'ERROR'}, "No data in simulation cache. Nothing to export in <" + cache_directory + ">")
return {'CANCELLED'}
print("FLIP Fluids Alembic Export: <" + self.filepath + ">")
hprops = context.scene.flip_fluid_helper
hprops.alembic_output_filepath = self.filepath
bpy.ops.flip_fluid_operators.helper_command_line_alembic_export('INVOKE_DEFAULT')
if hprops.alembic_export_engine == 'ALEMBIC_EXPORT_ENGINE_FLIP_FLUIDS':
self.alembic_export_engine_flip_fluids()
elif hprops.alembic_export_engine == 'ALEMBIC_EXPORT_ENGINE_BLENDER':
self.alembic_export_engine_blender()
else:
self.report({'WARNING'}, "Unknown Alembic Export Engine: " + hprops.alembic_export_engine)
return {'CANCELLED'}
return {'FINISHED'}
@@ -429,8 +429,7 @@ class FlipFluidIncreaseDecreaseCacheDirectory(bpy.types.Operator):
bl_description = ("Increase or decrease a numbered suffix on the cache directory." +
" Note: this will not rename an existing cache directory")
increment_mode = StringProperty(default="INCREASE")
exec(vcu.convert_attribute_to_28("increment_mode"))
increment_mode: StringProperty(default="INCREASE")
@classmethod
@@ -487,8 +486,7 @@ class FlipFluidIncreaseDecreaseRenderDirectory(bpy.types.Operator):
bl_description = ("Increase or decrease a numbered suffix on the render output directory." +
" Note: this will not rename an existing render output directory")
increment_mode = StringProperty(default="INCREASE")
exec(vcu.convert_attribute_to_28("increment_mode"))
increment_mode: StringProperty(default="INCREASE")
@classmethod
@@ -565,8 +563,7 @@ class FlipFluidIncreaseDecreaseCacheRenderVersion(bpy.types.Operator):
" directory and render output directory. Note: this will not rename an" +
" existing cache our render output directory")
increment_mode = StringProperty(default="INCREASE")
exec(vcu.convert_attribute_to_28("increment_mode"))
increment_mode: StringProperty(default="INCREASE")
@classmethod
@@ -14,7 +14,7 @@
# 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 bpy, os, pathlib, stat, subprocess, platform, random, shlex, shutil, traceback
import bpy, os, pathlib, stat, subprocess, platform, random, shlex, shutil, traceback, ctypes, json
from bpy.props import (
BoolProperty,
)
@@ -470,6 +470,46 @@ def get_command_line_script_filepath(script_filename):
return script_path
def get_flip_fluids_alembic_exporter_filepath():
executable_name = ""
system = platform.system()
if system == "Windows":
executable_name = "ff_alembic_exporter_windows.exe"
elif system == "Darwin":
executable_name = "ff_alembic_exporter_macos"
elif system == "Linux":
executable_name = "ff_alembic_exporter_linux"
executable_path = os.path.dirname(os.path.realpath(__file__))
executable_path = os.path.dirname(executable_path)
executable_path = os.path.join(executable_path, "ffengine", "lib", executable_name)
if not os.path.isfile(executable_path):
errmsg = "Unable to locate executable <" + executable_path + ">. Please contact the developers with this error."
raise Exception(errmsg)
return executable_path
def get_flip_fluids_alembic_exporter_lib_filepath():
executable_name = ""
system = platform.system()
if system == "Windows":
lib_name = "libffalembicengine.dll"
elif system == "Darwin":
lib_name = "libffalembicengine.dylib"
elif system == "Linux":
lib_name = "libffalembicengine.so"
lib_path = os.path.dirname(os.path.realpath(__file__))
lib_path = os.path.dirname(lib_path)
lib_path = os.path.join(lib_path, "ffengine", "lib", lib_name)
if not os.path.isfile(lib_path):
errmsg = "Unable to locate executable <" + lib_path + ">. Please contact the developers with this error."
raise Exception(errmsg)
return lib_path
def save_blend_file_before_launch(override_preferences=False):
prefs = vcu.get_addon_preferences()
if prefs.cmd_save_blend_file_before_launch or override_preferences:
@@ -539,11 +579,15 @@ def write_scripts_directory_readme():
f.write(readme_text)
def launch_command_universal_os(command_text, script_prefix_string, keep_window_open=True, skip_launch=False):
def launch_command_universal_os(command_text, script_prefix_string, keep_window_open=True, skip_launch=False, chcp=None):
system = platform.system()
if system == "Windows":
code_page = 65001
if chcp:
code_page = chcp
script_extension = ".bat"
script_header = "echo off\nchcp 65001\n\n"
script_header = "echo off\nchcp " + str(code_page) + "\n\n"
script_footer = ""
if keep_window_open:
script_footer = "\ncmd /k\n"
@@ -624,8 +668,7 @@ class FlipFluidHelperCommandLineBake(bpy.types.Operator):
" The .blend file will need to be saved for before using" +
" this operator for changes to take effect")
skip_launch = BoolProperty(False)
exec(vcu.convert_attribute_to_28("skip_launch"))
skip_launch: BoolProperty(False)
@classmethod
@@ -764,11 +807,9 @@ class FlipFluidHelperCommandLineRender(bpy.types.Operator):
bl_description = ("Launch a new command line window and start rendering the animation." +
" The .blend file will need to be saved before using this operator for changes to take effect")
use_turbo_tools = BoolProperty(False)
exec(vcu.convert_attribute_to_28("use_turbo_tools"))
use_turbo_tools: BoolProperty(False)
skip_launch = BoolProperty(False)
exec(vcu.convert_attribute_to_28("skip_launch"))
skip_launch: BoolProperty(False)
@classmethod
@@ -923,8 +964,7 @@ class FlipFluidHelperCommandLineRenderToClipboard(bpy.types.Operator):
bl_description = ("Copy command for rendering to your system clipboard." +
" The .blend file will need to be saved before running this command for changes to take effect")
use_turbo_tools = BoolProperty(False)
exec(vcu.convert_attribute_to_28("use_turbo_tools"))
use_turbo_tools: BoolProperty(False)
@classmethod
@@ -951,11 +991,9 @@ class FlipFluidHelperCommandLineRenderFrame(bpy.types.Operator):
bl_description = ("Launch a new command line window and start rendering the current timeline frame." +
" The .blend file will need to be saved before using this operator for changes to take effect")
use_turbo_tools = BoolProperty(False)
exec(vcu.convert_attribute_to_28("use_turbo_tools"))
use_turbo_tools: BoolProperty(False)
skip_launch = BoolProperty(False)
exec(vcu.convert_attribute_to_28("skip_launch"))
skip_launch: BoolProperty(False)
@classmethod
@@ -1022,14 +1060,13 @@ class FlipFluidHelperCommandLineRenderFrame(bpy.types.Operator):
class FlipFluidHelperCmdRenderFrameToClipboard(bpy.types.Operator):
class FlipFluidHelperCommandLineRenderFrameToClipboard(bpy.types.Operator):
bl_idname = "flip_fluid_operators.helper_cmd_render_frame_to_clipboard"
bl_label = "Launch Frame Render"
bl_description = ("Copy command for frame rendering to your system clipboard." +
" The .blend file will need to be saved before running this command for changes to take effect")
use_turbo_tools = BoolProperty(False)
exec(vcu.convert_attribute_to_28("use_turbo_tools"))
use_turbo_tools: BoolProperty(False)
@classmethod
@@ -1055,8 +1092,7 @@ class FlipFluidHelperCommandLineAlembicExport(bpy.types.Operator):
bl_description = ("Launch a new command line window and start exporting the simulation meshes to the Alembic (.abc) format." +
" The .blend file will need to be saved before using this operator for changes to take effect")
skip_launch = BoolProperty(False)
exec(vcu.convert_attribute_to_28("skip_launch"))
skip_launch: BoolProperty(False)
@classmethod
@@ -1085,7 +1121,7 @@ class FlipFluidHelperCommandLineAlembicExport(bpy.types.Operator):
return {'FINISHED'}
class FlipFluidHelperCmdAlembicExportToClipboard(bpy.types.Operator):
class FlipFluidHelperCommandLineAlembicExportToClipboard(bpy.types.Operator):
bl_idname = "flip_fluid_operators.helper_cmd_alembic_export_to_clipboard"
bl_label = "Launch Alembic Export"
bl_description = ("Copy command for Alembic export to your system clipboard." +
@@ -1109,6 +1145,75 @@ class FlipFluidHelperCmdAlembicExportToClipboard(bpy.types.Operator):
return {'FINISHED'}
class FlipFluidHelperCommandLineCustomAlembicExport(bpy.types.Operator):
bl_idname = "flip_fluid_operators.helper_cmd_custom_alembic_export"
bl_label = "Launch Alembic Export"
bl_description = ("Launch a new command line window and start exporting the simulation meshes to the Alembic (.abc) format." +
" The .blend file will need to be saved before using this operator for changes to take effect")
skip_launch: BoolProperty(False)
@classmethod
def poll(cls, context):
return context.scene.flip_fluid.get_domain_object() is not None and bool(bpy.data.filepath)
def get_export_frame_range(self):
frame_start = bpy.context.scene.frame_start
frame_end = bpy.context.scene.frame_end
hprops = bpy.context.scene.flip_fluid_helper
if hprops.alembic_frame_range_mode == 'FRAME_RANGE_CUSTOM':
frame_start = hprops.alembic_frame_range_custom.value_min
frame_end = hprops.alembic_frame_range_custom.value_max
return frame_start, frame_end
def execute(self, context):
save_blend_file_before_launch(override_preferences=False)
restore_blender_original_cwd()
script_path = get_command_line_script_filepath("flip_fluids_alembic_export.py")
command_text = "\"" + bpy.app.binary_path + "\" --background \"" + bpy.data.filepath + "\" --python \"" + script_path + "\""
script_filepath = launch_command_universal_os(command_text, "FF_ALEMBIC_EXPORT_", keep_window_open=True, skip_launch=self.skip_launch)
if not self.skip_launch:
info_msg = "Launched command line Alembic export window. If the Alembic export process did not begin,"
info_msg += " this may be caused by a conflict with another addon or a security feature of your OS that restricts"
info_msg += " automatic command execution. You may try running following script file manually:\n\n"
info_msg += script_filepath + "\n\n"
info_msg += "For more information on command line operators, visit our documentation:\n"
info_msg += "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Helper-Menu-Settings#command-line-alembic-export"
self.report({'INFO'}, info_msg)
return {'FINISHED'}
class FlipFluidHelperCommandLineCustomAlembicExportToClipboard(bpy.types.Operator):
bl_idname = "flip_fluid_operators.cmd_custom_alembic_export_to_clipboard"
bl_label = "Launch Alembic Export"
bl_description = ("Copy command for Alembic export to your system clipboard." +
" The .blend file will need to be saved before running this command for changes to take effect")
@classmethod
def poll(cls, context):
return context.scene.flip_fluid.get_domain_object() is not None and bool(bpy.data.filepath)
def execute(self, context):
bpy.ops.flip_fluid_operators.helper_cmd_custom_alembic_export('INVOKE_DEFAULT', skip_launch=True)
info_msg = "Copied the following Alembic export command to your clipboard:\n\n"
info_msg += bpy.context.window_manager.clipboard + "\n\n"
info_msg += "For more information on command line tools, visit our documentation:\n"
info_msg += "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Helper-Menu-Settings#command-line-alembic-export"
self.report({'INFO'}, info_msg)
return {'FINISHED'}
def get_render_output_info():
full_path = bpy.path.abspath(bpy.context.scene.render.filepath)
directory_path = full_path
@@ -1346,8 +1451,7 @@ class FlipFluidHelperCommandLineRenderPassAnimation(bpy.types.Operator):
bl_label = "Launch Render Pass Animation"
bl_description = ("Description: todo - launch render pass animation script")
skip_launch = BoolProperty(False)
exec(vcu.convert_attribute_to_28("skip_launch"))
skip_launch: BoolProperty(False)
@classmethod
@@ -1426,7 +1530,7 @@ class FlipFluidHelperCommandLineRenderPassAnimation(bpy.types.Operator):
self.report({'ERROR'}, errmsg)
return {'CANCELLED'}
if context.scene.render.engine == 'BLENDER_EEVEE':
if context.scene.render.engine == 'BLENDER_EEVEE' or context.scene.render.engine == 'BLENDER_EEVEE_NEXT':
self.report({'ERROR'}, "The EEVEE render engine is not supported for this feature. Set the render engine to Cycles, save, and try again.")
return {'CANCELLED'}
if context.scene.render.engine == 'BLENDER_WORKBENCH':
@@ -1510,8 +1614,7 @@ class FlipFluidHelperCommandLineRenderPassFrame(bpy.types.Operator):
bl_label = "Launch Render Pass Frame"
bl_description = ("Description: todo - launch render pass animation script")
skip_launch = BoolProperty(False)
exec(vcu.convert_attribute_to_28("skip_launch"))
skip_launch: BoolProperty(False)
@classmethod
@@ -1566,7 +1669,7 @@ class FlipFluidHelperCommandLineRenderPassFrame(bpy.types.Operator):
self.report({'ERROR'}, errmsg)
return {'CANCELLED'}
if context.scene.render.engine == 'BLENDER_EEVEE':
if context.scene.render.engine == 'BLENDER_EEVEE' or context.scene.render.engine == 'BLENDER_EEVEE_NEXT':
self.report({'ERROR'}, "The EEVEE render engine is not supported for this feature. Set the render engine to Cycles, save, and try again.")
return {'CANCELLED'}
if context.scene.render.engine == 'BLENDER_WORKBENCH':
@@ -1679,9 +1782,11 @@ def register():
bpy.utils.register_class(FlipFluidHelperCommandLineRender)
bpy.utils.register_class(FlipFluidHelperCommandLineRenderToClipboard)
bpy.utils.register_class(FlipFluidHelperCommandLineRenderFrame)
bpy.utils.register_class(FlipFluidHelperCmdRenderFrameToClipboard)
bpy.utils.register_class(FlipFluidHelperCommandLineRenderFrameToClipboard)
bpy.utils.register_class(FlipFluidHelperCommandLineAlembicExport)
bpy.utils.register_class(FlipFluidHelperCmdAlembicExportToClipboard)
bpy.utils.register_class(FlipFluidHelperCommandLineAlembicExportToClipboard)
bpy.utils.register_class(FlipFluidHelperCommandLineCustomAlembicExport)
bpy.utils.register_class(FlipFluidHelperCommandLineCustomAlembicExportToClipboard)
bpy.utils.register_class(FlipFluidHelperOpenRenderOutputFolder)
bpy.utils.register_class(FlipFluidHelperOpenCacheOutputFolder)
bpy.utils.register_class(FlipFluidHelperOpenAlembicOutputFolder)
@@ -1717,9 +1822,11 @@ def unregister():
bpy.utils.unregister_class(FlipFluidHelperCommandLineRender)
bpy.utils.unregister_class(FlipFluidHelperCommandLineRenderToClipboard)
bpy.utils.unregister_class(FlipFluidHelperCommandLineRenderFrame)
bpy.utils.unregister_class(FlipFluidHelperCmdRenderFrameToClipboard)
bpy.utils.unregister_class(FlipFluidHelperCommandLineRenderFrameToClipboard)
bpy.utils.unregister_class(FlipFluidHelperCommandLineAlembicExport)
bpy.utils.unregister_class(FlipFluidHelperCmdAlembicExportToClipboard)
bpy.utils.unregister_class(FlipFluidHelperCommandLineAlembicExportToClipboard)
bpy.utils.unregister_class(FlipFluidHelperCommandLineCustomAlembicExport)
bpy.utils.unregister_class(FlipFluidHelperCommandLineCustomAlembicExportToClipboard)
bpy.utils.unregister_class(FlipFluidHelperOpenRenderOutputFolder)
bpy.utils.unregister_class(FlipFluidHelperOpenCacheOutputFolder)
bpy.utils.unregister_class(FlipFluidHelperOpenAlembicOutputFolder)
@@ -1738,5 +1845,9 @@ def unregister():
# Remove shortcuts
for km, kmi in ADDON_KEYMAPS:
km.keymap_items.remove(kmi)
try:
# Keymap may be unavailable depending on context
km.keymap_items.remove(kmi)
except:
pass
ADDON_KEYMAPS.clear()
@@ -14,7 +14,8 @@
# 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 bpy, blf, math, colorsys
import bpy, blf, math, colorsys, gpu
from gpu_extras.batch import batch_for_shader
from bpy.props import (
IntProperty
@@ -25,10 +26,6 @@ from ..utils import ui_utils
from ..utils import version_compatibility_utils as vcu
from .. import render
if vcu.is_blender_28():
import gpu
from gpu_extras.batch import batch_for_shader
particle_vertices = []
particle_vertex_colors = []
@@ -88,51 +85,41 @@ def update_debug_force_field_geometry(context):
color_tuple = (color[0], color[1], color[2], 1.0)
particle_vertex_colors.append(color_tuple)
if vcu.is_blender_28():
global particle_shader
global particle_batch_draw
global particle_shader
global particle_batch_draw
vertex_shader = """
uniform mat4 ModelViewProjectionMatrix;
vertex_shader = """
uniform mat4 ModelViewProjectionMatrix;
in vec3 pos;
in vec4 color;
in vec3 pos;
in vec4 color;
out vec4 finalColor;
out vec4 finalColor;
void main()
{
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
finalColor = color;
}
"""
void main()
{
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
finalColor = color;
}
"""
fragment_shader = """
in vec4 finalColor;
out vec4 fragColor;
fragment_shader = """
in vec4 finalColor;
out vec4 fragColor;
void main()
{
fragColor = finalColor;
}
"""
void main()
{
fragColor = finalColor;
}
"""
if vcu.is_blender_35():
# Needed for support on MacOS Apple Silicon systems in Blender 3.5 or later
# Could possibly be a Blender regression bug why the below method no longer
# works in Blender 3.5 or later for MacOS. Should file a report.
shader_name = '3D_SMOOTH_COLOR'
if vcu.is_blender_40():
shader_name = 'SMOOTH_COLOR'
particle_shader = gpu.shader.from_builtin(shader_name)
else:
particle_shader = gpu.types.GPUShader(vertex_shader, fragment_shader)
shader_name = 'SMOOTH_COLOR'
particle_shader = gpu.shader.from_builtin(shader_name)
particle_batch_draw = batch_for_shader(
particle_shader, 'POINTS',
{"pos": particle_vertices, "color": particle_vertex_colors},
)
particle_batch_draw = batch_for_shader(
particle_shader, 'POINTS',
{"pos": particle_vertices, "color": particle_vertex_colors},
)
def _lerp_rgb(minc, maxc, factor, mode='RGB'):
@@ -185,50 +172,13 @@ class FlipFluidDrawForceField(bpy.types.Operator):
if vcu.get_object_hide_viewport(domain):
return
if not vcu.is_blender_28():
dlayers = [i for i,v in enumerate(domain.layers) if v]
slayers = [i for i,v in enumerate(context.scene.layers) if v]
if not (set(dlayers) & set(slayers)):
return
if vcu.is_blender_28():
global particle_shader
global particle_batch_draw
if vcu.is_blender_35():
# Warnings in Blender 3.5 when using bgl module, which is to
# be deprecated in Blender 3.7. Use gpu module instead.
gpu.state.point_size_set(dprops.debug.force_field_line_size)
else:
# only attempt to import bgl when necessary (older versions of Blender). In Blender >= 3.5,
# importing bgl generates a warning, and possibly an error in Blender >= 4.0.
import bgl
bgl.glPointSize(dprops.debug.force_field_line_size)
if vcu.is_blender_35():
# Can be drawn with depth in Blender 3.5 or later
gpu.state.depth_test_set('LESS_EQUAL')
gpu.state.depth_mask_set(True)
particle_batch_draw.draw(particle_shader)
if vcu.is_blender_35():
gpu.state.depth_mask_set(False)
else:
# only attempt to import bgl when necessary (older versions of Blender). In Blender >= 3.5,
# importing bgl generates a warning, and possibly an error in Blender >= 4.0.
import bgl
bgl.glPointSize(dprops.debug.force_field_line_size)
bgl.glBegin(bgl.GL_POINTS)
current_color = None
for i in range(len(particle_vertices)):
if current_color != particle_vertex_colors[i]:
current_color = particle_vertex_colors[i]
bgl.glColor4f(current_color[0], current_color[1], current_color[2], 1.0)
bgl.glVertex3f(*(particle_vertices[i]))
bgl.glEnd()
bgl.glPointSize(1)
bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
global particle_shader
global particle_batch_draw
gpu.state.point_size_set(dprops.debug.force_field_line_size)
gpu.state.depth_test_set('LESS_EQUAL')
gpu.state.depth_mask_set(True)
particle_batch_draw.draw(particle_shader)
gpu.state.depth_mask_set(False)
def modal(self, context, event):
@@ -25,9 +25,8 @@ from ..utils import ui_utils
from ..utils import version_compatibility_utils as vcu
from .. import render
if vcu.is_blender_28():
import gpu
from gpu_extras.batch import batch_for_shader
import gpu
from gpu_extras.batch import batch_for_shader
x_coords = []
@@ -195,33 +194,11 @@ class FlipFluidDrawDebugGrid(bpy.types.Operator):
if not dprops.debug.display_simulation_grid:
return
if not vcu.is_blender_28():
dlayers = [i for i,v in enumerate(domain.layers) if v]
slayers = [i for i,v in enumerate(context.scene.layers) if v]
if not (set(dlayers) & set(slayers)):
return
if dprops.debug.grid_display_mode == 'GRID_DISPLAY_SIMULATION':
isize, jsize, ksize, viewport_dx = dprops.simulation.get_viewport_grid_dimensions()
_, _, _, simulation_dx = dprops.simulation.get_simulation_grid_dimensions()
elif dprops.debug.grid_display_mode == 'GRID_DISPLAY_PREVIEW':
presolution = dprops.simulation.preview_resolution
"""
isize, jsize, ksize, viewport_dx = dprops.simulation.get_viewport_grid_dimensions(resolution=presolution)
_, _, _, simulation_dx = dprops.simulation.get_simulation_grid_dimensions(resolution=presolution)
else:
isize, jsize, ksize, viewport_dx = dprops.simulation.get_viewport_grid_dimensions()
_, _, _, simulation_dx = dprops.simulation.get_simulation_grid_dimensions()
if dprops.debug.grid_display_mode == 'GRID_DISPLAY_MESH':
isize *= (dprops.surface.subdivisions + 1)
jsize *= (dprops.surface.subdivisions + 1)
ksize *= (dprops.surface.subdivisions + 1)
viewport_dx /= (dprops.surface.subdivisions + 1)
"""
isize, jsize, ksize, viewport_dx = dprops.simulation.get_viewport_grid_dimensions(resolution=presolution)
_, _, _, simulation_dx = dprops.simulation.get_simulation_grid_dimensions(resolution=presolution)
elif dprops.debug.grid_display_mode == 'GRID_DISPLAY_MESH':
@@ -249,12 +226,8 @@ class FlipFluidDrawDebugGrid(bpy.types.Operator):
simulation_dx *= reduction
width = context.region.width
if vcu.is_blender_28():
height = 200
xstart = context.region.width - 400
else:
height = context.region.height
xstart = 50
height = 200
xstart = context.region.width - 400
font_id = 0
try:
@@ -360,12 +333,6 @@ class FlipFluidDrawDebugGrid(bpy.types.Operator):
if vcu.get_object_hide_viewport(domain):
return
if not vcu.is_blender_28():
dlayers = [i for i,v in enumerate(domain.layers) if v]
slayers = [i for i,v in enumerate(context.scene.layers) if v]
if not (set(dlayers) & set(slayers)):
return
x_color = dprops.debug.x_grid_color
y_color = dprops.debug.y_grid_color
z_color = dprops.debug.z_grid_color
@@ -373,86 +340,49 @@ class FlipFluidDrawDebugGrid(bpy.types.Operator):
# Draw
display_grid = dprops.debug.display_simulation_grid
if vcu.is_blender_28():
line_draw_mode = '3D_UNIFORM_COLOR'
if vcu.is_blender_36():
# 3D/2D prefix deprecated in recent versions of Blender
line_draw_mode = 'UNIFORM_COLOR'
if display_grid and dprops.debug.enabled_debug_grids[2]:
shader = gpu.shader.from_builtin(line_draw_mode)
batch = batch_for_shader(shader, 'LINES', {"pos": z_coords})
shader.bind()
shader.uniform_float("color", (z_color[0], z_color[1], z_color[2], 1.0))
line_draw_mode = 'UNIFORM_COLOR'
if vcu.is_blender_35():
# Can be drawn with depth in Blender 3.5 or later
gpu.state.depth_test_set('LESS_EQUAL')
gpu.state.depth_mask_set(True)
batch.draw(shader)
if vcu.is_blender_35():
gpu.state.depth_mask_set(False)
if display_grid and dprops.debug.enabled_debug_grids[1]:
shader = gpu.shader.from_builtin(line_draw_mode)
batch = batch_for_shader(shader, 'LINES', {"pos": y_coords})
shader.bind()
shader.uniform_float("color", (y_color[0], y_color[1], y_color[2], 1.0))
if vcu.is_blender_35():
# Can be drawn with depth in Blender 3.5 or later
gpu.state.depth_test_set('LESS_EQUAL')
gpu.state.depth_mask_set(True)
batch.draw(shader)
if vcu.is_blender_35():
gpu.state.depth_mask_set(False)
if display_grid and dprops.debug.enabled_debug_grids[0]:
shader = gpu.shader.from_builtin(line_draw_mode)
batch = batch_for_shader(shader, 'LINES', {"pos": x_coords})
shader.bind()
shader.uniform_float("color", (x_color[0], x_color[1], x_color[2], 1.0))
if vcu.is_blender_35():
# Can be drawn with depth in Blender 3.5 or later
gpu.state.depth_test_set('LESS_EQUAL')
gpu.state.depth_mask_set(True)
batch.draw(shader)
if vcu.is_blender_35():
gpu.state.depth_mask_set(False)
if dprops.debug.display_domain_bounds:
shader = gpu.shader.from_builtin(line_draw_mode)
batch = batch_for_shader(shader, 'LINES', {"pos": bounds_coords})
shader.bind()
shader.uniform_float("color", (bounds_color[0], bounds_color[1], bounds_color[2], 1.0))
if vcu.is_blender_35():
# Can be drawn with depth in Blender 3.5 or later
gpu.state.depth_test_set('LESS_EQUAL')
gpu.state.depth_mask_set(True)
batch.draw(shader)
if vcu.is_blender_35():
gpu.state.depth_mask_set(False)
else:
import bgl
bgl.glLineWidth(1)
bgl.glBegin(bgl.GL_LINES)
if display_grid and dprops.debug.enabled_debug_grids[2]:
shader = gpu.shader.from_builtin(line_draw_mode)
batch = batch_for_shader(shader, 'LINES', {"pos": z_coords})
shader.bind()
shader.uniform_float("color", (z_color[0], z_color[1], z_color[2], 1.0))
if display_grid and dprops.debug.enabled_debug_grids[2]:
bgl.glColor4f(*z_color, 1.0)
for c in z_coords:
bgl.glVertex3f(*c)
if display_grid and dprops.debug.enabled_debug_grids[1]:
bgl.glColor4f(*y_color, 1.0)
for c in y_coords:
bgl.glVertex3f(*c)
if display_grid and dprops.debug.enabled_debug_grids[0]:
bgl.glColor4f(*x_color, 1.0)
for c in x_coords:
bgl.glVertex3f(*c)
if dprops.debug.display_domain_bounds:
bgl.glColor4f(*(bounds_color), 1.0)
for c in bounds_coords:
bgl.glVertex3f(*c)
gpu.state.depth_test_set('LESS_EQUAL')
gpu.state.depth_mask_set(True)
batch.draw(shader)
gpu.state.depth_mask_set(False)
bgl.glEnd()
bgl.glLineWidth(1)
bgl.glEnable(bgl.GL_DEPTH_TEST)
bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
if display_grid and dprops.debug.enabled_debug_grids[1]:
shader = gpu.shader.from_builtin(line_draw_mode)
batch = batch_for_shader(shader, 'LINES', {"pos": y_coords})
shader.bind()
shader.uniform_float("color", (y_color[0], y_color[1], y_color[2], 1.0))
gpu.state.depth_test_set('LESS_EQUAL')
gpu.state.depth_mask_set(True)
batch.draw(shader)
gpu.state.depth_mask_set(False)
if display_grid and dprops.debug.enabled_debug_grids[0]:
shader = gpu.shader.from_builtin(line_draw_mode)
batch = batch_for_shader(shader, 'LINES', {"pos": x_coords})
shader.bind()
shader.uniform_float("color", (x_color[0], x_color[1], x_color[2], 1.0))
gpu.state.depth_test_set('LESS_EQUAL')
gpu.state.depth_mask_set(True)
batch.draw(shader)
gpu.state.depth_mask_set(False)
if dprops.debug.display_domain_bounds:
shader = gpu.shader.from_builtin(line_draw_mode)
batch = batch_for_shader(shader, 'LINES', {"pos": bounds_coords})
shader.bind()
shader.uniform_float("color", (bounds_color[0], bounds_color[1], bounds_color[2], 1.0))
gpu.state.depth_test_set('LESS_EQUAL')
gpu.state.depth_mask_set(True)
batch.draw(shader)
gpu.state.depth_mask_set(False)
def modal(self, context, event):
@@ -25,9 +25,8 @@ from ..utils import ui_utils
from ..utils import version_compatibility_utils as vcu
from .. import render
if vcu.is_blender_28():
import gpu
from gpu_extras.batch import batch_for_shader
import gpu
from gpu_extras.batch import batch_for_shader
particle_vertices = []
@@ -87,51 +86,16 @@ def update_debug_particle_geometry(context):
particle_vertices.append(particles[pidx])
particle_vertex_colors.append(color_tuple)
if vcu.is_blender_28():
global particle_shader
global particle_batch_draw
global particle_shader
global particle_batch_draw
vertex_shader = """
uniform mat4 ModelViewProjectionMatrix;
shader_name = 'SMOOTH_COLOR'
particle_shader = gpu.shader.from_builtin(shader_name)
in vec3 pos;
in vec4 color;
out vec4 finalColor;
void main()
{
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
finalColor = color;
}
"""
fragment_shader = """
in vec4 finalColor;
out vec4 fragColor;
void main()
{
fragColor = finalColor;
}
"""
if vcu.is_blender_35():
# Needed for support on MacOS Apple Silicon systems in Blender 3.5 or later
# Could possibly be a Blender regression bug why the below method no longer
# works in Blender 3.5 or later for MacOS. Should file a report.
shader_name = '3D_SMOOTH_COLOR'
if vcu.is_blender_40():
shader_name = 'SMOOTH_COLOR'
particle_shader = gpu.shader.from_builtin(shader_name)
else:
particle_shader = gpu.types.GPUShader(vertex_shader, fragment_shader)
particle_batch_draw = batch_for_shader(
particle_shader, 'POINTS',
{"pos": particle_vertices, "color": particle_vertex_colors},
)
particle_batch_draw = batch_for_shader(
particle_shader, 'POINTS',
{"pos": particle_vertices, "color": particle_vertex_colors},
)
def _get_color_ranges(pdata, num_colors):
@@ -224,50 +188,13 @@ class FlipFluidDrawGLParticles(bpy.types.Operator):
if vcu.get_object_hide_viewport(domain):
return
if not vcu.is_blender_28():
dlayers = [i for i,v in enumerate(domain.layers) if v]
slayers = [i for i,v in enumerate(context.scene.layers) if v]
if not (set(dlayers) & set(slayers)):
return
if vcu.is_blender_28():
global particle_shader
global particle_batch_draw
if vcu.is_blender_35():
# Warnings in Blender 3.5 when using bgl module, which is to
# be deprecated in Blender 3.7. Use gpu module instead.
gpu.state.point_size_set(dprops.debug.particle_size)
else:
# only attempt to import bgl when necessary (older versions of Blender). In Blender >= 3.5,
# importing bgl generates a warning, and possibly an error in Blender >= 4.0.
import bgl
bgl.glPointSize(dprops.debug.particle_size)
if vcu.is_blender_35():
# Can be drawn with depth in Blender 3.5 or later
gpu.state.depth_test_set('LESS_EQUAL')
gpu.state.depth_mask_set(True)
particle_batch_draw.draw(particle_shader)
if vcu.is_blender_35():
gpu.state.depth_mask_set(False)
else:
# only attempt to import bgl when necessary (older versions of Blender). In Blender >= 3.5,
# importing bgl generates a warning, and possibly an error in Blender >= 4.0.
import bgl
bgl.glPointSize(dprops.debug.particle_size)
bgl.glBegin(bgl.GL_POINTS)
current_color = None
for i in range(len(particle_vertices)):
if current_color != particle_vertex_colors[i]:
current_color = particle_vertex_colors[i]
bgl.glColor4f(current_color[0], current_color[1], current_color[2], 1.0)
bgl.glVertex3f(*(particle_vertices[i]))
bgl.glEnd()
bgl.glPointSize(1)
bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
global particle_shader
global particle_batch_draw
gpu.state.point_size_set(dprops.debug.particle_size)
gpu.state.depth_test_set('LESS_EQUAL')
gpu.state.depth_mask_set(True)
particle_batch_draw.draw(particle_shader)
gpu.state.depth_mask_set(False)
def modal(self, context, event):
@@ -28,14 +28,9 @@ class FlipFluidDisplayError(bpy.types.Operator):
bl_label = ""
bl_description = ""
error_message = StringProperty()
exec(vcu.convert_attribute_to_28("error_message"))
error_description = StringProperty()
exec(vcu.convert_attribute_to_28("error_description"))
popup_width = IntProperty(default=400)
exec(vcu.convert_attribute_to_28("popup_width"))
error_message: StringProperty()
error_description: StringProperty()
popup_width: IntProperty(default=400)
def draw(self, context):
@@ -55,14 +55,11 @@ class FlipFluidHelperRemesh(bpy.types.Operator):
" of the input geometry. Use the link next to this operator to view documentation and a video guide" +
" for using this feature")
skip_hide_render_objects = BoolProperty(True)
exec(vcu.convert_attribute_to_28("skip_hide_render_objects"))
skip_hide_render_objects: BoolProperty(True)
apply_object_modifiers = BoolProperty(True)
exec(vcu.convert_attribute_to_28("apply_object_modifiers"))
apply_object_modifiers: BoolProperty(True)
convert_objects_to_mesh = BoolProperty(True)
exec(vcu.convert_attribute_to_28("convert_objects_to_mesh"))
convert_objects_to_mesh: BoolProperty(True)
@classmethod
@@ -446,8 +443,7 @@ class FlipFluidHelperSelectObjects(bpy.types.Operator):
bl_label = "Select Objects"
bl_description = "Select all FLIP Fluid objects of this type"
object_type = StringProperty("TYPE_NONE")
exec(vcu.convert_attribute_to_28("object_type"))
object_type: StringProperty("TYPE_NONE")
@classmethod
@@ -802,8 +798,7 @@ class FlipFluidHelperAddObjects(bpy.types.Operator):
bl_label = "Add Objects"
bl_description = "Add selected objects as FLIP Fluid objects"
object_type = StringProperty("TYPE_NONE")
exec(vcu.convert_attribute_to_28("object_type"))
object_type: StringProperty("TYPE_NONE")
@classmethod
def poll(cls, context):
@@ -1014,8 +1009,7 @@ class FlipFluidHelperDeleteWhitewaterObjects(bpy.types.Operator):
" Warning: deleting these objects will also remove any modifications such as added" +
" modifiers and materials")
whitewater_type = StringProperty("TYPE_ALL")
exec(vcu.convert_attribute_to_28("whitewater_type"))
whitewater_type: StringProperty("TYPE_ALL")
@classmethod
@@ -1053,7 +1047,7 @@ class FlipFluidHelperOrganizeOutliner(bpy.types.Operator):
@classmethod
def poll(cls, context):
return vcu.is_blender_28()
return True
def initialize_child_collection(self, context, child_name, parent_collection):
@@ -1159,7 +1153,7 @@ class FlipFluidHelperSeparateFLIPMeshes(bpy.types.Operator):
@classmethod
def poll(cls, context):
dprops = context.scene.flip_fluid.get_domain_properties()
return vcu.is_blender_28() and dprops is not None
return dprops is not None
def initialize_child_collection(self, context, child_name, parent_collection):
@@ -1237,7 +1231,7 @@ class FlipFluidHelperUndoOrganizeOutliner(bpy.types.Operator):
@classmethod
def poll(cls, context):
return vcu.is_blender_28()
return True
def unlink_collection(self, context, collection_name):
@@ -1287,7 +1281,7 @@ class FlipFluidHelperUndoSeparateFLIPMeshes(bpy.types.Operator):
@classmethod
def poll(cls, context):
dprops = context.scene.flip_fluid.get_domain_properties()
return vcu.is_blender_28() and dprops is not None
return dprops is not None
def unlink_collection(self, context, collection_name):
@@ -1331,8 +1325,7 @@ class FlipFluidHelperSetObjectViewportDisplay(bpy.types.Operator):
bl_label = "Object Viewport Display"
bl_description = "Set how selected objects are displayed/rendered in the viewport"
display_mode = StringProperty("TYPE_NONE")
exec(vcu.convert_attribute_to_28("display_mode"))
display_mode: StringProperty("TYPE_NONE")
@classmethod
@@ -1365,8 +1358,7 @@ class FlipFluidHelperSetObjectRenderDisplay(bpy.types.Operator):
bl_label = "Object Render Display"
bl_description = "Set selected objects visiblility in the render"
hide_render = BoolProperty(False)
exec(vcu.convert_attribute_to_28("hide_render"))
hide_render: BoolProperty(False)
@classmethod
@@ -1568,7 +1560,7 @@ class FlipFluidEnableColorAttributeTooltip(bpy.types.Operator):
class FlipFluidEnableViscosityAttribute(bpy.types.Operator):
bl_idname = "flip_fluid_operators.enable_viscosity_attribute"
bl_label = "Enable Viscosity Attribute"
bl_description = "Enable viscosity solver and variable viscosity attribute in the Domain FLIP Fluid World panel"
bl_description = "Enable viscosity solver and variable viscosity attribute in the Domain World panel"
@classmethod
def poll(cls, context):
@@ -1606,10 +1598,50 @@ class FlipFluidEnableViscosityAttributeTooltip(bpy.types.Operator):
return {'FINISHED'}
class FlipFluidEnableDensityAttribute(bpy.types.Operator):
bl_idname = "flip_fluid_operators.enable_density_attribute"
bl_label = "Enable Density Attribute"
bl_description = "Enable variable density solver and attribute in the Domain World panel"
@classmethod
def poll(cls, context):
return context.scene.flip_fluid.get_domain_object() is not None
def execute(self, context):
dprops = context.scene.flip_fluid.get_domain_properties()
dprops.world.enable_density_attribute = True
return {'FINISHED'}
class FlipFluidEnableDensityAttributeMenu(bpy.types.Menu):
bl_label = ""
bl_idname = "FLIP_FLUID_MENUS_MT_enable_density_attribute_menu"
def draw(self, context):
self.layout.operator("flip_fluid_operators.enable_density_attribute")
class FlipFluidEnableDensityAttributeTooltip(bpy.types.Operator):
bl_idname = "flip_fluid_operators.enable_density_attribute_tooltip"
bl_label = "Enable Density Attribute"
bl_description = "Click to enable the variable density solver and attribute in the Domain World panel"
@classmethod
def poll(cls, context):
return context.scene.flip_fluid.get_domain_object() is not None
def execute(self, context):
bpy.ops.wm.call_menu(name="FLIP_FLUID_MENUS_MT_enable_density_attribute_menu")
return {'FINISHED'}
class FlipFluidEnableLifetimeAttribute(bpy.types.Operator):
bl_idname = "flip_fluid_operators.enable_lifetime_attribute"
bl_label = "Enable Lifetime Attribute"
bl_description = "Enable lifetime attribute in the Domain FLIP Fluid Surface and Domain FLIP Fluid Particles panel"
bl_description = "Enable lifetime attribute in the Domain Surface and/or Domain Particles panel"
@classmethod
def poll(cls, context):
@@ -1619,7 +1651,8 @@ class FlipFluidEnableLifetimeAttribute(bpy.types.Operator):
def execute(self, context):
dprops = context.scene.flip_fluid.get_domain_properties()
dprops.surface.enable_lifetime_attribute = True
dprops.particles.enable_lifetime_attribute = True
dprops.particles.enable_fluid_particle_lifetime_attribute = True
dprops.whitewater.enable_lifetime_attribute = True
return {'FINISHED'}
@@ -1634,7 +1667,7 @@ class FlipFluidEnableLifetimeAttributeMenu(bpy.types.Menu):
class FlipFluidEnableLifetimeAttributeTooltip(bpy.types.Operator):
bl_idname = "flip_fluid_operators.enable_lifetime_attribute_tooltip"
bl_label = "Enable Lifetime Attribute"
bl_description = "Click to enable the lifetime attribute in the Domain FLIP Fluid Surface and Domain FLIP Fluid Particles panel"
bl_description = "Click to enable the lifetime attribute in the Domain Surface and/or Domain Particles panel"
@classmethod
@@ -1650,7 +1683,7 @@ class FlipFluidEnableLifetimeAttributeTooltip(bpy.types.Operator):
class FlipFluidEnableSourceIDAttribute(bpy.types.Operator):
bl_idname = "flip_fluid_operators.enable_source_id_attribute"
bl_label = "Enable Source ID Attribute"
bl_description = "Enable source ID attribute in the Domain FLIP Fluid Surface and FLIP Fluid Particles panel"
bl_description = "Enable source ID attribute in the Domain Surface and/or Particles panel"
@classmethod
def poll(cls, context):
@@ -1675,7 +1708,7 @@ class FlipFluidEnableSourceIDAttributeMenu(bpy.types.Menu):
class FlipFluidEnableSourceIDAttributeTooltip(bpy.types.Operator):
bl_idname = "flip_fluid_operators.enable_source_id_attribute_tooltip"
bl_label = "Enable Source ID Attribute"
bl_description = "Click to enable the source ID attribute in the Domain FLIP Fluid Surface and FLIP Fluid Particles panel"
bl_description = "Click to enable the source ID attribute in the Domain Surface and/or Domain Particles panel"
@classmethod
@@ -1689,9 +1722,6 @@ class FlipFluidEnableSourceIDAttributeTooltip(bpy.types.Operator):
def is_geometry_node_point_cloud_detected(bl_mesh_cache_object=None):
if not vcu.is_blender_31():
return False
try:
dprops = bpy.context.scene.flip_fluid.get_domain_properties()
if bl_mesh_cache_object is None:
@@ -1723,7 +1753,7 @@ def is_geometry_node_point_cloud_detected(bl_mesh_cache_object=None):
def update_geometry_node_material(bl_object, resource_name):
if not vcu.is_blender_31() or bl_object is None:
if bl_object is None:
return
gn_modifier = None
@@ -1769,6 +1799,13 @@ def add_geometry_node_modifier(target_object, resource_filepath, resource_name):
return gn_modifier
def get_geometry_node_modifier(target_object, resource_name):
for mod in target_object.modifiers:
if mod.type == 'NODES' and mod.name == resource_name:
return mod
return None
class FlipFluidHelperInitializeMotionBlur(bpy.types.Operator):
bl_idname = "flip_fluid_operators.helper_initialize_motion_blur"
bl_label = "Initialize Motion Blur"
@@ -1776,8 +1813,7 @@ class FlipFluidHelperInitializeMotionBlur(bpy.types.Operator):
" This will be applied to the fluid surface, fluid particles, and whitewater particles if enabled." +
" Node groups can be viewed in the geometry nodes editor and modifier")
resource_prefix = StringProperty(default="FF_GeometryNodes")
exec(vcu.convert_attribute_to_28("resource_prefix"))
resource_prefix: StringProperty(default="FF_GeometryNodes")
@classmethod
@@ -1786,10 +1822,6 @@ class FlipFluidHelperInitializeMotionBlur(bpy.types.Operator):
def apply_modifier_settings(self, target_object, gn_modifier):
gn_modifier["Input_2_use_attribute"] = True
gn_modifier["Input_2_attribute_name"] = 'flip_velocity'
gn_modifier["Output_3_attribute_name"] = 'velocity'
gn_name = gn_modifier.name
if gn_name.startswith("FF_GeometryNodesSurface"):
# Depending on FLIP Fluids version, the GN set up may not
@@ -1815,30 +1847,15 @@ class FlipFluidHelperInitializeMotionBlur(bpy.types.Operator):
except:
pass
try:
# Enable Point Cloud
gn_modifier["Input_9"] = True
except:
pass
try:
# Enable Instancing
gn_modifier["Input_10"] = False
except:
pass
def execute(self, context):
if not vcu.is_blender_31():
self.report({'INFO'}, "Blender 3.1 or later is required for this feature")
return {'CANCELLED'}
if not context.scene.flip_fluid.is_domain_in_active_scene():
self.report({"ERROR"},
"Active scene must contain domain object to use this operator. Select the scene that contains the domain object and try again.")
return {'CANCELLED'}
if context.scene.render.engine != 'CYCLES':
unsupported_render_engines = ['BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT', 'BLENDER_WORKBENCH']
if context.scene.render.engine in unsupported_render_engines:
context.scene.render.engine = 'CYCLES'
self.report({'INFO'}, "Setting render engine to Cycles")
if not context.scene.render.use_motion_blur:
@@ -1848,15 +1865,15 @@ class FlipFluidHelperInitializeMotionBlur(bpy.types.Operator):
dprops = context.scene.flip_fluid.get_domain_properties()
if not dprops.surface.enable_velocity_vector_attribute:
dprops.surface.enable_velocity_vector_attribute = True
self.report({'INFO'}, "Enabled generation of fluid surface velocity vector attributes in FLIP Fluid Surface panel (baking required)")
self.report({'INFO'}, "Enabled generation of fluid surface velocity vector attributes in Domain Surface panel (baking required)")
if not dprops.particles.enable_fluid_particle_velocity_vector_attribute:
dprops.particles.enable_fluid_particle_velocity_vector_attribute = True
self.report({'INFO'}, "Enabled generation of fluid particle velocity vector attributes in FLIP Fluid Particles panel (baking required)")
self.report({'INFO'}, "Enabled generation of fluid particle velocity vector attributes in Domain Particles panel (baking required)")
if not dprops.whitewater.enable_velocity_vector_attribute:
dprops.whitewater.enable_velocity_vector_attribute = True
self.report({'INFO'}, "Enabled generation of whitewater velocity vector attributes in FLIP Fluid Whitewater (baking required)")
self.report({'INFO'}, "Enabled generation of whitewater velocity vector attributes in Domain Whitewater (baking required)")
blend_filename = "geometry_nodes_library.blend"
surface_resource = self.resource_prefix + "Surface"
@@ -1943,8 +1960,7 @@ class FlipFluidHelperRemoveMotionBlur(bpy.types.Operator):
" operator will not disable the Domain surface/particles/whitewater velocity attribute settings")
resource_prefix = StringProperty(default="FF_GeometryNodes")
exec(vcu.convert_attribute_to_28("resource_prefix"))
resource_prefix: StringProperty(default="FF_GeometryNodes")
@classmethod
@@ -1953,10 +1969,6 @@ class FlipFluidHelperRemoveMotionBlur(bpy.types.Operator):
def execute(self, context):
if not vcu.is_blender_31():
self.report({'INFO'}, "Blender 3.1 or later is required for this feature")
return {'CANCELLED'}
if not context.scene.flip_fluid.is_domain_in_active_scene():
self.report({"ERROR"},
"Active scene must contain domain object to use this operator. Select the scene that contains the domain object and try again.")
@@ -2019,8 +2031,7 @@ class FlipFluidHelperToggleMotionBlurRendering(bpy.types.Operator):
bl_description = ("Toggle motion blur rendering for the simulation meshes on or off. This operator will enable or" +
" disable the simulations mesh object and geometry node settings for motion blur rendering")
enable_motion_blur_rendering = BoolProperty(default=True)
exec(vcu.convert_attribute_to_28("enable_motion_blur_rendering"))
enable_motion_blur_rendering: BoolProperty(default=True)
@classmethod
@@ -2070,13 +2081,207 @@ class FlipFluidHelperToggleMotionBlurRendering(bpy.types.Operator):
return {'FINISHED'}
class FlipFluidHelperUpdateGeometryNodeModifiers(bpy.types.Operator):
bl_idname = "flip_fluid_operators.helper_update_geometry_node_modifiers"
bl_label = "Update Geometry Node Modifiers"
bl_description = ("Update the fluid surface, particle, and whitewater geometry nodes modifiers to the current addon version and transfer settings." +
" This operator will not delete existing FLIP Fluids modifiers or datablocks. Existing modifiers will be renamed with a" +
" BACKUP prefix and disabled in the modifier stack. This backup can be removed if not wanted")
resource_prefix: StringProperty(default="FF_GeometryNodes")
@classmethod
def poll(cls, context):
return context.scene.flip_fluid.get_domain_object() is not None
def transfer_gn_modifer_settings(self, old_gn_modifier, new_gn_modifier, old_new_key_pairs):
for key in old_new_key_pairs:
old_key = key[0]
new_key = key[1]
if old_key in old_gn_modifier:
try:
new_gn_modifier[new_key] = old_gn_modifier[old_key]
except:
pass
def transfer_gn_modifier_settings_surface(self, old_gn_modifier, new_gn_modifier):
# Old Key, New Key
keys = [
("Input_6", "Input_6"), # Enable Motion Blur
("Input_4", "Input_4"), # Motion Blur Scale
]
self.transfer_gn_modifer_settings(old_gn_modifier, new_gn_modifier, keys)
def transfer_gn_modifier_settings_fluid_particle(self, old_gn_modifier, new_gn_modifier):
# Old Key, New Key
keys = [
("Input_5", "Input_5"), # Material
("Input_8", "Input_8"), # Enable Motion Blur
("Input_4", "Input_4"), # Motion Blur Scale
("Input_6", "Input_6"), # Particle Scale
("Socket_2", "Socket_2"), # Particle Scale Random
("Socket_1", "Socket_1"), # Fading Width
("Socket_0", "Socket_0"), # Fading Strength
("Socket_4", "Socket_4"), # Fading Density
]
self.transfer_gn_modifer_settings(old_gn_modifier, new_gn_modifier, keys)
def transfer_gn_modifier_settings_whitewater(self, old_gn_modifier, new_gn_modifier):
# Old Key, New Key
keys = [
("Input_5", "Input_5"), # Material
("Input_8", "Input_8"), # Enable Motion Blur
("Input_4", "Input_4"), # Motion Blur Scale
("Input_6", "Input_6"), # Particle Scale
("Socket_2", "Socket_2"), # Particle Scale Random
("Socket_1", "Socket_1"), # Fading Width
("Socket_0", "Socket_0"), # Fading Strength
("Socket_4", "Socket_4"), # Fading Density
]
self.transfer_gn_modifer_settings(old_gn_modifier, new_gn_modifier, keys)
def get_ff_geometry_node_modifiers(self, bl_object):
modifiers = []
if bl_object is None:
return modifiers
for mod in bl_object.modifiers:
if mod.type == "NODES" and mod.node_group and mod.node_group.name.startswith("FF_GeometryNodes"):
modifiers.append(mod)
return modifiers
def execute(self, context):
if not context.scene.flip_fluid.is_domain_in_active_scene():
self.report({"ERROR"},
"Active scene must contain domain object to use this operator. Select the scene that contains the domain object and try again.")
return {'CANCELLED'}
dprops = context.scene.flip_fluid.get_domain_properties()
# Gather Blender cache objects
surface_mesh_caches = [dprops.mesh_cache.surface]
surface_cache_objects = []
for m in surface_mesh_caches:
bl_object = m.get_cache_object()
if bl_object is not None:
surface_cache_objects.append(bl_object)
fluid_particle_mesh_caches = [dprops.mesh_cache.particles]
fluid_particle_cache_objects = []
for m in fluid_particle_mesh_caches:
bl_object = m.get_cache_object()
if bl_object is not None:
fluid_particle_cache_objects.append(bl_object)
whitewater_mesh_caches = [
dprops.mesh_cache.foam,
dprops.mesh_cache.bubble,
dprops.mesh_cache.spray,
dprops.mesh_cache.dust
]
whitewater_cache_objects = []
for m in whitewater_mesh_caches:
bl_object = m.get_cache_object()
if bl_object is not None:
whitewater_cache_objects.append(bl_object)
bl_cache_objects = surface_cache_objects + fluid_particle_cache_objects + whitewater_cache_objects
# Search for the last FF_GeometryNodes modifier in the stack for each cache object for transferring settings
surface_gn_modifiers = []
for bl_object in surface_cache_objects:
existing_gn_modifiers = self.get_ff_geometry_node_modifiers(bl_object)
if existing_gn_modifiers:
surface_gn_modifiers.append(existing_gn_modifiers[-1])
else:
surface_gn_modifiers.append(None)
fluid_particle_gn_modifiers = []
for bl_object in fluid_particle_cache_objects:
existing_gn_modifiers = self.get_ff_geometry_node_modifiers(bl_object)
if existing_gn_modifiers:
fluid_particle_gn_modifiers.append(existing_gn_modifiers[-1])
else:
fluid_particle_gn_modifiers.append(None)
whitewater_gn_modifiers = []
for bl_object in whitewater_cache_objects:
existing_gn_modifiers = self.get_ff_geometry_node_modifiers(bl_object)
if existing_gn_modifiers:
whitewater_gn_modifiers.append(existing_gn_modifiers[-1])
else:
whitewater_gn_modifiers.append(None)
# Disable existing FF_GeometryNode modifiers and rename with BACKUP_ prefix
for bl_object in bl_cache_objects:
existing_gn_modifiers = self.get_ff_geometry_node_modifiers(bl_object)
for mod in existing_gn_modifiers:
mod.show_viewport = False
mod.show_render = False
mod.show_expanded = False
mod.name = "BACKUP_" + mod.name
mod.node_group.name = "BACKUP_" + mod.node_group.name
# Initialize current FF_GeometryNode modifiers
geometry_nodes_library = "geometry_nodes_library.blend"
parent_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
resource_filepath = os.path.join(parent_path, "resources", "geometry_nodes", geometry_nodes_library)
surface_resource = self.resource_prefix + "Surface"
fluid_particle_resource = self.resource_prefix + "FluidParticles"
whitewater_foam_resource = self.resource_prefix + "WhitewaterFoam"
whitewater_bubble_resource = self.resource_prefix + "WhitewaterBubble"
whitewater_spray_resource = self.resource_prefix + "WhitewaterSpray"
whitewater_dust_resource = self.resource_prefix + "WhitewaterDust"
for idx, bl_surface in enumerate(surface_cache_objects):
old_gn_modifier = surface_gn_modifiers[idx]
new_gn_modifier = add_geometry_node_modifier(bl_surface, resource_filepath, surface_resource)
if old_gn_modifier and new_gn_modifier:
self.transfer_gn_modifier_settings_surface(old_gn_modifier, new_gn_modifier)
for idx, bl_fluid_particle in enumerate(fluid_particle_cache_objects):
old_gn_modifier = fluid_particle_gn_modifiers[idx]
new_gn_modifier = add_geometry_node_modifier(bl_fluid_particle, resource_filepath, fluid_particle_resource)
if old_gn_modifier and new_gn_modifier:
self.transfer_gn_modifier_settings_fluid_particle(old_gn_modifier, new_gn_modifier)
for idx, bl_whitewater in enumerate(whitewater_cache_objects):
whitewater_resource = ""
if bl_whitewater == dprops.mesh_cache.foam.get_cache_object():
whitewater_resource = whitewater_foam_resource
elif bl_whitewater == dprops.mesh_cache.bubble.get_cache_object():
whitewater_resource = whitewater_bubble_resource
elif bl_whitewater == dprops.mesh_cache.spray.get_cache_object():
whitewater_resource = whitewater_spray_resource
elif bl_whitewater == dprops.mesh_cache.dust.get_cache_object():
whitewater_resource = whitewater_dust_resource
old_gn_modifier = whitewater_gn_modifiers[idx]
new_gn_modifier = add_geometry_node_modifier(bl_whitewater, resource_filepath, whitewater_resource)
if old_gn_modifier and new_gn_modifier:
self.transfer_gn_modifier_settings_whitewater(old_gn_modifier, new_gn_modifier)
self.report({'INFO'}, "Updated FLIP Fluids Geometry Node Modifiers")
return {'FINISHED'}
class FlipFluidHelperInitializeCacheObjects(bpy.types.Operator):
bl_idname = "flip_fluid_operators.helper_initialize_cache_objects"
bl_label = "Initialize Cache Objects"
bl_description = ("Initialize simulation meshes, modifiers, and data")
cache_object_type = StringProperty(default="CACHE_OBJECT_TYPE_NONE")
exec(vcu.convert_attribute_to_28("cache_object_type"))
cache_object_type: StringProperty(default="CACHE_OBJECT_TYPE_NONE")
@classmethod
@@ -2139,8 +2344,7 @@ class FlipFluidHelperStableRendering28(bpy.types.Operator):
" during render (Blender > Render > Lock Interface) and is highly"
" recommended")
enable_state = BoolProperty(True)
exec(vcu.convert_attribute_to_28("enable_state"))
enable_state: BoolProperty(True)
@classmethod
@@ -2188,8 +2392,7 @@ class FlipFluidHelperSaveBlendFile(bpy.types.Operator):
bl_label = "Save File"
bl_description = "Open the Blender file window to save the current .blend file"
save_as_blend_file = BoolProperty(default=True)
exec(vcu.convert_attribute_to_28("save_as_blend_file"))
save_as_blend_file: BoolProperty(default=True)
@classmethod
@@ -2241,8 +2444,7 @@ class FlipFluidHelperBatchExportAnimatedMesh(bpy.types.Operator):
bl_description = "Enable or Disable the 'Export Animated Mesh' option for all objects in list"
enable_state = BoolProperty(True)
exec(vcu.convert_attribute_to_28("enable_state"))
enable_state: BoolProperty(True)
@classmethod
@@ -2265,8 +2467,7 @@ class FlipFluidHelperBatchSkipReexport(bpy.types.Operator):
bl_description = "Enable or Disable the 'Skip Re-Export' option for all objects in list"
enable_state = BoolProperty(True)
exec(vcu.convert_attribute_to_28("enable_state"))
enable_state: BoolProperty(True)
@classmethod
@@ -2289,8 +2490,7 @@ class FlipFluidHelperBatchForceReexport(bpy.types.Operator):
bl_description = "Enable or Disable the 'Force Re-Export On Next Bake' option for all objects in list"
enable_state = BoolProperty(True)
exec(vcu.convert_attribute_to_28("enable_state"))
enable_state: BoolProperty(True)
@classmethod
@@ -2538,20 +2738,12 @@ class FlipFluidCopySettingsFromActive(bpy.types.Operator):
def toggle_cycles_ray_visibility(self, obj, is_enabled):
# Cycles may not be enabled in the user's preferences
try:
if vcu.is_blender_30():
obj.visible_camera = is_enabled
obj.visible_diffuse = is_enabled
obj.visible_glossy = is_enabled
obj.visible_transmission = is_enabled
obj.visible_volume_scatter = is_enabled
obj.visible_shadow = is_enabled
else:
obj.cycles_visibility.camera = is_enabled
obj.cycles_visibility.transmission = is_enabled
obj.cycles_visibility.diffuse = is_enabled
obj.cycles_visibility.scatter = is_enabled
obj.cycles_visibility.glossy = is_enabled
obj.cycles_visibility.shadow = is_enabled
obj.visible_camera = is_enabled
obj.visible_diffuse = is_enabled
obj.visible_glossy = is_enabled
obj.visible_transmission = is_enabled
obj.visible_volume_scatter = is_enabled
obj.visible_shadow = is_enabled
except:
pass
@@ -4507,11 +4699,7 @@ class FlipFluidPassesImportMedia(bpy.types.Operator):
bl_idname = "flip_fluid.passes_import_media"
bl_label = "Import Media"
option_path_supports_blend_relative = set()
if vcu.is_blender_45():
# required for relative path support in Blender 4.5+
# https://docs.blender.org/api/4.5/bpy_types_enum_items/property_flag_items.html#rna-enum-property-flag-items
option_path_supports_blend_relative = {'PATH_SUPPORTS_BLEND_RELATIVE'}
option_path_supports_blend_relative = {'PATH_SUPPORTS_BLEND_RELATIVE'}
filter_glob: StringProperty(
default="*.png;*.jpg;*.jpeg;*.bmp;*.tiff;*.tif;*.mp4;*.avi;*.mov",
@@ -5992,6 +6180,7 @@ def register():
FlipFluidHelperInitializeMotionBlur,
FlipFluidHelperRemoveMotionBlur,
FlipFluidHelperToggleMotionBlurRendering,
FlipFluidHelperUpdateGeometryNodeModifiers,
FlipFluidHelperInitializeCacheObjects,
FlipFluidHelperStableRendering279,
FlipFluidHelperStableRendering28,
@@ -6013,6 +6202,9 @@ def register():
FlipFluidEnableViscosityAttribute,
FlipFluidEnableViscosityAttributeMenu,
FlipFluidEnableViscosityAttributeTooltip,
FlipFluidEnableDensityAttribute,
FlipFluidEnableDensityAttributeMenu,
FlipFluidEnableDensityAttributeTooltip,
FlipFluidEnableLifetimeAttribute,
FlipFluidEnableLifetimeAttributeMenu,
FlipFluidEnableLifetimeAttributeTooltip,
@@ -6103,6 +6295,7 @@ def unregister():
bpy.utils.unregister_class(FlipFluidHelperInitializeMotionBlur)
bpy.utils.unregister_class(FlipFluidHelperRemoveMotionBlur)
bpy.utils.unregister_class(FlipFluidHelperToggleMotionBlurRendering)
bpy.utils.unregister_class(FlipFluidHelperUpdateGeometryNodeModifiers)
bpy.utils.unregister_class(FlipFluidHelperInitializeCacheObjects)
bpy.utils.unregister_class(FlipFluidHelperStableRendering279)
bpy.utils.unregister_class(FlipFluidHelperStableRendering28)
@@ -6124,6 +6317,9 @@ def unregister():
bpy.utils.unregister_class(FlipFluidEnableViscosityAttribute)
bpy.utils.unregister_class(FlipFluidEnableViscosityAttributeMenu)
bpy.utils.unregister_class(FlipFluidEnableViscosityAttributeTooltip)
bpy.utils.unregister_class(FlipFluidEnableDensityAttribute)
bpy.utils.unregister_class(FlipFluidEnableDensityAttributeMenu)
bpy.utils.unregister_class(FlipFluidEnableDensityAttributeTooltip)
bpy.utils.unregister_class(FlipFluidEnableLifetimeAttribute)
bpy.utils.unregister_class(FlipFluidEnableLifetimeAttributeMenu)
bpy.utils.unregister_class(FlipFluidEnableLifetimeAttributeTooltip)
@@ -47,8 +47,7 @@ class FLIPFluidPreferencesExportUserData(bpy.types.Operator):
bl_description = ("Creates a backup of your user settings and presets as a" +
" .zip file. All user data will be lost after uninstalling the addon.")
filepath = StringProperty(subtype="FILE_PATH")
exec(vcu.convert_attribute_to_28("filepath"))
filepath: StringProperty(subtype="FILE_PATH")
@classmethod
@@ -180,12 +179,11 @@ class FLIPFluidPreferencesImportUserData(bpy.types.Operator, ImportHelper):
bl_description = "Load user settings and presets from a previous installation"
filename_ext = "*.zip"
filter_glob = StringProperty(
filter_glob: StringProperty(
default="*.zip",
options={'HIDDEN'},
maxlen=255,
)
exec(vcu.convert_attribute_to_28("filter_glob"))
@@ -264,12 +262,11 @@ class FLIPFluidInstallMixboxPlugin(bpy.types.Operator, ImportHelper):
" Fluids addon downloads")
filename_ext = "*.plugin"
filter_glob = StringProperty(
filter_glob: StringProperty(
default="*.plugin;*.zip",
options={'HIDDEN'},
maxlen=255,
)
exec(vcu.convert_attribute_to_28("filter_glob"))
@classmethod
@@ -377,12 +374,11 @@ class FLIPFluidInstallPresetLibrary(bpy.types.Operator, ImportHelper):
" The Preset Scenes file can be found in the FLIP Fluids addon downloads")
filename_ext = "*.zip"
filter_glob = StringProperty(
filter_glob: StringProperty(
default="*.zip",
options={'HIDDEN'},
maxlen=255,
)
exec(vcu.convert_attribute_to_28("filter_glob"))
@classmethod
@@ -512,9 +508,7 @@ class FLIPFluidInstallPresetLibrary(bpy.types.Operator, ImportHelper):
for lib_entry in bl_filepaths.asset_libraries:
if self.is_path_equal(lib_entry.path, preset_library_directory):
lib_entry.name = preset_library_name
if vcu.is_blender_35():
# Only available in Blender >= 3.5
lib_entry.import_method = 'APPEND'
lib_entry.import_method = 'APPEND'
installation_utils.update_preset_library_installation_status()
success_message = "The Preset Scenes Library has been installed successfully into the Blender Asset Browser."
@@ -529,11 +523,9 @@ class FLIPFluidSelectPresetLibraryFolder(bpy.types.Operator):
bl_label = "Install Preset Folder"
bl_description = ("Select an existing Preset Library installation folder and add it to the Blender Asset Browser")
directory = bpy.props.StringProperty(name="Directory", options={"HIDDEN"})
exec(vcu.convert_attribute_to_28("directory"))
directory: bpy.props.StringProperty(name="Directory", options={"HIDDEN"})
filter_folder = bpy.props.BoolProperty(default=True, options={"HIDDEN"})
exec(vcu.convert_attribute_to_28("filter_folder"))
filter_folder: bpy.props.BoolProperty(default=True, options={"HIDDEN"})
@classmethod
@@ -643,9 +635,7 @@ class FLIPFluidSelectPresetLibraryFolder(bpy.types.Operator):
lib_version_str = "v" + str(version[0]) + "." + str(version[1]) + "." + str(version[2])
preset_library_name = "FLIP Fluids Addon Presets " + lib_version_str
lib_entry.name = preset_library_name
if vcu.is_blender_35():
# Only available in Blender >= 3.5
lib_entry.import_method = 'APPEND'
lib_entry.import_method = 'APPEND'
installation_utils.update_preset_library_installation_status()
success_message = "The Preset Scenes Library has been installed successfully into the Blender Asset Browser."
@@ -667,8 +657,7 @@ class FLIPFluidPresetLibraryCopyInstallLocation(bpy.types.Operator):
bl_description = ("Copy the preset library location to the Install Location field and" +
" system clipboard. The install location is the parent directory of the path listed below")
install_location = StringProperty(default="")
exec(vcu.convert_attribute_to_28("install_location"))
install_location: StringProperty(default="")
def execute(self, context):
preferences = vcu.get_addon_preferences()
@@ -683,8 +672,7 @@ class FLIPFluidUninstallPresetLibrary(bpy.types.Operator):
bl_description = ("Uninstall the preset library. The preset library will be removed from" +
" the Blender Asset Browser and the files deleted from your system")
install_info_json_string = StringProperty(default="")
exec(vcu.convert_attribute_to_28("install_info_json_string"))
install_info_json_string: StringProperty(default="")
def tag_redraw(self, context):
@@ -751,8 +739,7 @@ class FLIPFluidUninstallPresetLibrary(bpy.types.Operator):
class VersionDataTextEntry(bpy.types.PropertyGroup):
text = StringProperty(default="")
exec(vcu.convert_attribute_to_28("text"))
text: StringProperty(default="")
def get_gpu_string():
@@ -899,12 +886,11 @@ def get_system_info_dict():
addons_list = []
addons_string = "Unknown"
try:
if vcu.is_blender_42():
for addon in bpy.context.preferences.addons:
addon_name = addon.module
addon_name = addon_name.split('.')[-1]
if addon_name and addon_name not in default_addons:
addons_list.append(addon_name)
for addon in bpy.context.preferences.addons:
addon_name = addon.module
addon_name = addon_name.split('.')[-1]
if addon_name and addon_name not in default_addons:
addons_list.append(addon_name)
if addons_list:
addons_string = ', '.join(addons_list)
else:
@@ -913,7 +899,7 @@ def get_system_info_dict():
print(traceback.format_exc())
print(e)
developer_tools_string = "Uknown"
developer_tools_string = "Unknown"
try:
preferences = vcu.get_addon_preferences()
developer_tools_string = "Enabled" if preferences.enable_extra_features else "Disabled"
@@ -1198,6 +1184,7 @@ def get_system_info_dict():
d = {}
d['blender_version'] = blender_version
d['addon_version'] = bl_info.get('description', "Missing Version Label")
d['addon_support_license'] = installation_utils.get_support_license_label()
d['operating_system'] = platform.platform()
d['cpu'] = cpu_string
d['threads'] = threads_string
@@ -1256,6 +1243,7 @@ class FlipFluidReportBugPrefill(bpy.types.Operator):
user_info += "#### System and Blend File Information\n\n"
user_info += "**Blender Version:** " + sys_info['blender_version'] + "\n"
user_info += "**Addon Version:** " + sys_info['addon_version'] + "\n"
user_info += "**Addon Build:** " + sys_info['addon_support_license'] + "\n"
user_info += "**OS:** " + sys_info['operating_system'] + "\n"
user_info += "**GPU:** " + sys_info['gpu'] + "\n"
user_info += "**CPU:** " + sys_info['cpu'] + "\n"
@@ -1318,6 +1306,7 @@ def get_system_info_string():
user_info = ""
user_info += "Blender Version: " + sys_info['blender_version'] + "\n"
user_info += "Addon Version: " + sys_info['addon_version'] + "\n"
user_info += "Addon Build: " + sys_info['addon_support_license'] + "\n"
user_info += "OS: " + sys_info['operating_system'] + "\n"
user_info += "GPU: " + sys_info['gpu'] + "\n"
user_info += "CPU: " + sys_info['cpu'] + "\n"
@@ -1383,8 +1372,7 @@ class FlipFluidOpenPreferences(bpy.types.Operator):
bl_label = "FLIP Fluids Preferences"
bl_description = ("Open the FLIP Fluids addon preferences menu")
view_mode = StringProperty(default="NONE")
exec(vcu.convert_attribute_to_28("view_mode"))
view_mode: StringProperty(default="NONE")
def execute(self, context):
@@ -1402,12 +1390,8 @@ class FlipFluidOpenPreferences(bpy.types.Operator):
if self.view_mode in valid_view_modes:
prefs = vcu.get_addon_preferences()
prefs.preferences_menu_view_mode = self.view_mode
if vcu.is_blender_42():
module_name = base_package
else:
module_name = installation_utils.get_module_name()
bpy.ops.preferences.addon_show(module=module_name)
bpy.ops.preferences.addon_show(module=base_package)
return {'FINISHED'}
@@ -1435,9 +1419,7 @@ class FLIPFLUIDS_MT_help_menu(bpy.types.Menu):
def draw(self, context):
self.layout.operator("flip_fluid_operators.report_bug_prefill", icon="URL")
self.layout.operator("flip_fluid_operators.copy_system_info", icon="COPYDOWN")
if vcu.is_blender_28():
self.layout.operator("flip_fluid_operators.open_preferences", icon="PREFERENCES").view_mode = 'NONE'
self.layout.operator("flip_fluid_operators.open_preferences", icon="PREFERENCES").view_mode = 'NONE'
def draw_flip_fluids_help_menu(self, context):
@@ -243,8 +243,7 @@ class FlipFluidPresetCreateNewPresetEnableAll(bpy.types.Operator):
bl_label = "Enable All"
bl_description = "Enable all preset attributes"
collection_id = StringProperty(default="")
exec(vcu.convert_attribute_to_28("collection_id"))
collection_id: StringProperty(default="")
@classmethod
@@ -271,8 +270,7 @@ class FlipFluidPresetCreateNewPresetDisableAll(bpy.types.Operator):
bl_label = "Disable All"
bl_description = "Disable all preset attributes"
collection_id = StringProperty(default="")
exec(vcu.convert_attribute_to_28("collection_id"))
collection_id: StringProperty(default="")
@classmethod
def poll(cls, context):
@@ -299,8 +297,7 @@ class FlipFluidPresetCreateNewPresetEnableAuto(bpy.types.Operator):
bl_description = ("Automatically enable/disable preset attributes by" +
" comparing to system default settings")
collection_id = StringProperty(default="")
exec(vcu.convert_attribute_to_28("collection_id"))
collection_id: StringProperty(default="")
@classmethod
def poll(cls, context):
@@ -936,8 +933,7 @@ class FlipFluidPresetDisplayInfo(bpy.types.Operator):
bl_label = "Preset Info"
bl_description = "Display preset information"
identifier = StringProperty(default="")
exec(vcu.convert_attribute_to_28("identifier"))
identifier: StringProperty(default="")
@classmethod
def poll(cls, context):
@@ -1245,12 +1241,11 @@ class SelectPresetPackageZipFile(bpy.types.Operator, ImportHelper):
bl_label = "Select Package Zipfile"
filename_ext = "*.zip"
filter_glob = StringProperty(
filter_glob: StringProperty(
default="*.zip",
options={'HIDDEN'},
maxlen=255,
)
exec(vcu.convert_attribute_to_28("filter_glob"))
def execute(self, context):
@@ -1691,8 +1686,7 @@ class FlipFluidPresetRemovePresetFromStack(bpy.types.Operator):
bl_label = "Remove From Preset Stack"
bl_description = "Remove from preset stack"
stack_index = IntProperty(default=-1)
exec(vcu.convert_attribute_to_28("stack_index"))
stack_index: IntProperty(default=-1)
@classmethod
def poll(cls, context):
@@ -1714,8 +1708,7 @@ class FlipFluidPresetMovePresetUpInStack(bpy.types.Operator):
bl_label = "Move Up"
bl_description = "Move preset up in the stack"
stack_index = IntProperty(default=-1)
exec(vcu.convert_attribute_to_28("stack_index"))
stack_index: IntProperty(default=-1)
@classmethod
def poll(cls, context):
@@ -1737,8 +1730,7 @@ class FlipFluidPresetMovePresetDownInStack(bpy.types.Operator):
bl_label = "Move Down"
bl_description = "Move preset down in the stack"
stack_index = IntProperty(default=-1)
exec(vcu.convert_attribute_to_28("stack_index"))
stack_index: IntProperty(default=-1)
@classmethod
def poll(cls, context):
@@ -1760,8 +1752,7 @@ class FlipFluidPresetApplyAndRemoveFromStack(bpy.types.Operator):
bl_label = "Apply"
bl_description = "Apply preset and remove from the stack"
stack_index = IntProperty(default=-1)
exec(vcu.convert_attribute_to_28("stack_index"))
stack_index: IntProperty(default=-1)
@classmethod
def poll(cls, context):
@@ -1804,8 +1795,7 @@ class FlipFluidPresetEditPresetEnableAll(bpy.types.Operator):
bl_label = "Enable All"
bl_description = "Enable all preset attributes"
collection_id = StringProperty(default="")
exec(vcu.convert_attribute_to_28("collection_id"))
collection_id: StringProperty(default="")
@classmethod
def poll(cls, context):
@@ -1831,8 +1821,7 @@ class FlipFluidPresetEditPresetDisableAll(bpy.types.Operator):
bl_label = "Disable All"
bl_description = "Disable all preset attributes"
collection_id = StringProperty(default="")
exec(vcu.convert_attribute_to_28("collection_id"))
collection_id: StringProperty(default="")
@classmethod
def poll(cls, context):
@@ -125,7 +125,7 @@
},
{
"path": "domain.simulation.frame_rate_custom",
"value": 24.0
"value": 25.0
},
{
"path": "domain.simulation.time_scale_mode",
@@ -289,17 +289,6 @@
"path": "domain.surface.remove_mesh_near_domain_distance",
"value": 1
},
{
"path": "domain.surface.remove_mesh_near_domain_sides",
"value": [
true,
true,
true,
true,
true,
true
]
},
{
"path": "domain.surface.smoothing_value",
"value": 0.5
@@ -1015,10 +1004,6 @@
"path": "domain.debug.display_console_output",
"value": true
},
{
"path": "domain.debug.display_render_passes_console_output",
"value": false
},
{
"path": "domain.stats.cache_info_type",
"value": "CACHE_INFO"
@@ -169,7 +169,7 @@ visibility_settings = {
"world": {"camera": False, "diffuse": True, "glossy": False, "transmission": False, "scatter": False},
"selected_objects": {"camera": False, "diffuse": True, "glossy": True, "transmission": True, "scatter": True, "shadow": True, "is_shadow_catcher": False, "is_holdout": False},
"fg_elements": {"camera": True, "diffuse": True, "glossy": True, "transmission": False, "scatter": True, "shadow": True, "is_shadow_catcher": False, "is_holdout": True},
"bg_elements": {"camera": True, "diffuse": True, "glossy": True, "transmission": False, "scatter": True, "shadow": True, "is_shadow_catcher": True, "is_holdout": False},
"bg_elements": {"camera": True, "diffuse": True, "glossy": True, "transmission": False, "scatter": True, "shadow": True, "is_shadow_catcher": False, "is_holdout": False},
"ref_elements": {"camera": True, "diffuse": True, "glossy": True, "transmission": False, "scatter": True, "shadow": True, "is_shadow_catcher": False, "is_holdout": True},
"film_transparent": True,
"transparent_glass": True,
@@ -30,9 +30,8 @@ from ..utils import version_compatibility_utils as vcu
class DomainAdvancedProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
min_max_time_steps_per_frame = NewMinMaxIntProperty(
min_max_time_steps_per_frame: NewMinMaxIntProperty(
name_min="Min Substeps",
description_min="Minimum number of substeps per frame calculation",
min_min=1, max_min=1000000,
@@ -44,24 +43,24 @@ class DomainAdvancedProperties(bpy.types.PropertyGroup):
min_max=1, max_max=1000000,
soft_max_max=100,
default_max=24,
); exec(conv("min_max_time_steps_per_frame"))
enable_adaptive_obstacle_time_stepping = BoolProperty(
)
enable_adaptive_obstacle_time_stepping: BoolProperty(
name="Enable Adaptive Time Stepping for Obstacles",
description="Include obstacle velocities when calculating number"
" of frame substeps. Enabling may improve the accuracy of"
" fluid-solid interaction for fast moving obstacles, but"
" may take longer to simulate",
default = False,
); exec(conv("enable_adaptive_obstacle_time_stepping"))
enable_adaptive_force_field_time_stepping = BoolProperty(
)
enable_adaptive_force_field_time_stepping: BoolProperty(
name="Enable Adaptive Time Stepping for Force Fields",
description="Include force field velocities when calculating number"
" of frame substeps. Enabling may improve the accuracy of"
" fluid-forcefield interaction for fast moving force fields, but"
" will take longer to simulate",
default = False,
); exec(conv("enable_adaptive_force_field_time_stepping"))
particle_jitter_factor = FloatProperty(
)
particle_jitter_factor: FloatProperty(
name="Particle Jitter",
description="Amount of random jitter that is added to newly spawned"
" fluid particles. Higher values may improve simulation accuracy",
@@ -69,8 +68,8 @@ class DomainAdvancedProperties(bpy.types.PropertyGroup):
default=1.0,
precision=2,
subtype='FACTOR',
); exec(conv("particle_jitter_factor"))
jitter_surface_particles = BoolProperty(
)
jitter_surface_particles: BoolProperty(
name="Jitter Surface Particles",
description="If disabled, a random jitter position will only be applied to particles within"
" the interior of the Inflow/Fluid object shape. If enabled, all emitted particles"
@@ -79,31 +78,31 @@ class DomainAdvancedProperties(bpy.types.PropertyGroup):
" Enabling is recommended for fluid particle effects and results in"
" more natural particle generation",
default=False,
); exec(conv("jitter_surface_particles"))
pressure_solver_max_iterations = IntProperty(
)
pressure_solver_max_iterations: IntProperty(
name="Pressure Solver Max Iterations",
description="Maximum number of iterations that the pressure solver is allowed"
" to run during a substep. The default value of 900 is often a good choice and does"
" not need to be changed. See documentation for more information on this setting",
min=1, soft_max=10000,
default=900,
); exec(conv("pressure_solver_max_iterations"))
viscosity_solver_max_iterations = IntProperty(
)
viscosity_solver_max_iterations: IntProperty(
name="Viscosity Solver Max Iterations",
description="Maximum number of iterations that the viscosity solver is allowed"
" to run during a substep. The default value of 900 is often a good choice and does"
" not need to be changed. See documentation for more information on this setting",
min=1, soft_max=10000,
default=900,
); exec(conv("viscosity_solver_max_iterations"))
velocity_transfer_method = EnumProperty(
)
velocity_transfer_method: EnumProperty(
name="Velocity Transfer Method",
description="Simulation method to use",
items=types.velocity_transfer_methods,
default='VELOCITY_TRANSFER_METHOD_FLIP',
options={'HIDDEN'},
); exec(conv("velocity_transfer_method"))
PICFLIP_ratio = FloatProperty(
)
PICFLIP_ratio: FloatProperty(
name="PIC/FLIP Ratio",
description="Ratio of PIC velocity to FLIP velocity update mixture."
" PIC velocity method is not very accurate, but stable. FLIP"
@@ -114,16 +113,16 @@ class DomainAdvancedProperties(bpy.types.PropertyGroup):
default=0.05,
precision=2,
subtype='FACTOR',
); exec(conv("PICFLIP_ratio"))
PICAPIC_ratio = FloatProperty(
)
PICAPIC_ratio: FloatProperty(
name="PIC/APIC Ratio",
description="Placeholder",
min=0.0, max=1.0,
default=0.00,
precision=2,
subtype='FACTOR',
); exec(conv("PICAPIC_ratio"))
CFL_condition_number = IntProperty(
)
CFL_condition_number: IntProperty(
name="Safety Factor (CFL Number)",
description="Maximum number of voxels that a particle can travel"
" in a single substep. A larger number may speed up simulation"
@@ -131,8 +130,8 @@ class DomainAdvancedProperties(bpy.types.PropertyGroup):
" cost of simulation accuracy",
min=1, max=30,
default=5,
); exec(conv("CFL_condition_number"))
enable_extreme_velocity_removal = BoolProperty(
)
enable_extreme_velocity_removal: BoolProperty(
name="Remove particles with extreme velocities",
description="Attempt to remove extreme particle velocities that"
" cause the simulator to exceed the maximum number of allowed"
@@ -141,8 +140,8 @@ class DomainAdvancedProperties(bpy.types.PropertyGroup):
" this option outside of experimentation and testing. Disabling"
" can result in unstable simulations and/or extreme simulation times",
default=True,
); exec(conv("enable_extreme_velocity_removal"))
enable_gpu_features = BoolProperty(
)
enable_gpu_features: BoolProperty(
name="Enable GPU Features",
description="Enable simulator to accelerate some computations"
" with your GPU device. TIP: Compare simulation performance"
@@ -150,28 +149,28 @@ class DomainAdvancedProperties(bpy.types.PropertyGroup):
" hardware setup. Note: you may only notice a difference on"
" higher resolution simulations",
default=True
); exec(conv("enable_gpu_features"))
num_threads_auto_detect = IntProperty(
)
num_threads_auto_detect: IntProperty(
name="Threads",
description="Number of threads to use simultaneously while simulating",
min=1, max=1024,
default=1,
); exec(conv("num_threads_auto_detect"))
num_threads_fixed = IntProperty(
)
num_threads_fixed: IntProperty(
name="Threads",
description="Number of threads to use simultaneously while simulating",
min=1, max=1024,
default=4,
); exec(conv("num_threads_fixed"))
threading_mode = EnumProperty(
)
threading_mode: EnumProperty(
name="Threading Mode",
description="Determing the amount of simulation threads used",
items=types.threading_modes,
default='THREADING_MODE_AUTO_DETECT',
update=lambda self, context: self.initialize_num_threads_auto_detect(),
options={'HIDDEN'},
); exec(conv("threading_mode"))
enable_fracture_optimization = BoolProperty(
)
enable_fracture_optimization: BoolProperty(
name="Enable Fracture Optimizations",
description="Enable optimizations when using animated fracture simulations as"
" FLIP obstacles. These optimizations can greatly improve simulation performance"
@@ -181,30 +180,30 @@ class DomainAdvancedProperties(bpy.types.PropertyGroup):
" this option can increase memory requirements",
default = False,
options={'HIDDEN'},
); exec(conv("enable_fracture_optimization"))
enable_asynchronous_meshing = BoolProperty(
)
enable_asynchronous_meshing: BoolProperty(
name="Enable Async Meshing",
description="Run mesh generation process in a separate thread while"
" the simulation is running. May increase simulation performance"
" but will use more RAM if enabled",
default = True,
); exec(conv("enable_asynchronous_meshing"))
precompute_static_obstacles = BoolProperty(
)
precompute_static_obstacles: BoolProperty(
name="Precompute Static Obstacles",
description="Precompute data for static obstacles. If enabled,"
" the simulator will avoid recomputing data for non-animated"
" obstacles. Increases simulation performance but will use"
" more RAM if enabled",
default = True,
); exec(conv("precompute_static_obstacles"))
reserve_temporary_grids = BoolProperty(
)
reserve_temporary_grids: BoolProperty(
name="Reserve Temporary Grid Memory",
description="Reserve space in memory for temporary grids. Increases"
" simulation performance for scenes with animated or keyframed"
" obstacles but will use more RAM if enabled",
default = True,
); exec(conv("reserve_temporary_grids"))
disable_changing_topology_warning = BoolProperty(
)
disable_changing_topology_warning: BoolProperty(
name="Disable Changing Topology Warning",
description="Disable warning that is displayed when exporting an"
" animated mesh with changing topology. WARNING: mesh velocity"
@@ -213,23 +212,17 @@ class DomainAdvancedProperties(bpy.types.PropertyGroup):
" not be able to push around the fluid",
default=False,
options={'HIDDEN'},
); exec(conv("disable_changing_topology_warning"))
)
surface_tension_substeps_exceeded_tooltip = BoolProperty(
surface_tension_substeps_exceeded_tooltip: BoolProperty(
name="Warning: Not Enough Max Substeps",
description="The estimated number of Surface Tension substeps per frame exceeds the Max Frame"
" Substeps value. This can cause an unstable simulation. Either decrease the amount of"
" Surface Tension in the FLIP Fluid World panel to lower the number of required substeps or"
" increase the number of allowed Max Frame Substeps in the FLIP Fluid Advanced panel",
default=True,
); exec(conv("surface_tension_substeps_exceeded_tooltip"))
frame_substeps_expanded = BoolProperty(default=True); exec(conv("frame_substeps_expanded"))
simulation_method_expanded = BoolProperty(default=True); exec(conv("simulation_method_expanded"))
simulation_stability_expanded = BoolProperty(default=False); exec(conv("simulation_stability_expanded"))
multithreading_expanded = BoolProperty(default=True); exec(conv("multithreading_expanded"))
warnings_and_errors_expanded = BoolProperty(default=False); exec(conv("warnings_and_errors_expanded"))
)
def register_preset_properties(self, registry, path):
add = registry.add_property
@@ -32,37 +32,36 @@ IS_SAVESTATE_ENUMS_INITIALIZED = False
class DomainBakeProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
is_export_operator_running = BoolProperty(default=False); exec(conv("is_export_operator_running"))
is_export_operator_cancelled = BoolProperty(default=False); exec(conv("is_export_operator_cancelled"))
export_progress = FloatProperty(default=0.0); exec(conv("export_progress"))
export_stage = StringProperty(default=""); exec(conv("export_stage"))
is_export_operator_running: BoolProperty(default=False)
is_export_operator_cancelled: BoolProperty(default=False)
export_progress: FloatProperty(default=0.0)
export_stage: StringProperty(default="")
export_filename = StringProperty(default='flipdata.sim'); exec(conv("export_filename"))
export_directory_name = StringProperty(default='export'); exec(conv("export_directory_name"))
export_filepath = StringProperty(default=""); exec(conv("export_filepath"))
export_success = BoolProperty(default=False); exec(conv("export_success"))
export_filename: StringProperty(default='flipdata.sim')
export_directory_name: StringProperty(default='export')
export_filepath: StringProperty(default="")
export_success: BoolProperty(default=False)
is_simulation_running = BoolProperty(default=False); exec(conv("is_simulation_running"))
bake_progress = FloatProperty(default=0.0); exec(conv("bake_progress"))
is_bake_initialized = BoolProperty(default=False); exec(conv("is_bake_initialized"))
is_bake_cancelled = BoolProperty(default=False); exec(conv("is_bake_cancelled"))
num_baked_frames = IntProperty(default=0); exec(conv("num_baked_frames"))
is_simulation_running: BoolProperty(default=False)
bake_progress: FloatProperty(default=0.0)
is_bake_initialized: BoolProperty(default=False)
is_bake_cancelled: BoolProperty(default=False)
num_baked_frames: IntProperty(default=0)
is_autosave_available = BoolProperty(default=False); exec(conv("is_autosave_available"))
is_autosave_last_frame = BoolProperty(default=False); exec(conv("is_autosave_last_frame"))
is_safe_to_exit = BoolProperty(default=False); exec(conv("is_safe_to_exit"))
autosave_frame_id = IntProperty(default=-1); exec(conv("autosave_frame_id"))
autosave_frame = IntProperty(default=-1); exec(conv("autosave_frame"))
is_autosave_available: BoolProperty(default=False)
is_autosave_last_frame: BoolProperty(default=False)
is_safe_to_exit: BoolProperty(default=False)
autosave_frame_id: IntProperty(default=-1)
autosave_frame: IntProperty(default=-1)
original_frame_start = IntProperty(
original_frame_start: IntProperty(
name="Start Frame",
description="First frame of the simulation cache. Cannot be changed"
" after beginning a simulation",
default=-1,
options={'HIDDEN'},
); exec(conv("original_frame_start"))
)
def register_preset_properties(self, registry, path):
@@ -28,18 +28,15 @@ from .. import exit_handler
from ..utils import version_compatibility_utils as vcu
class DomainCacheProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
temp_directory = vcu.get_blender_preferences_temporary_directory()
default_cache_directory_str = os.path.join(temp_directory, "untitled_flip_fluid_cache")
option_path_supports_blend_relative = set()
if vcu.is_blender_45():
# required for relative path support in Blender 4.5+
# https://docs.blender.org/api/4.5/bpy_types_enum_items/property_flag_items.html#rna-enum-property-flag-items
option_path_supports_blend_relative = {'PATH_SUPPORTS_BLEND_RELATIVE'}
# required for relative path support in Blender 4.5+
# https://docs.blender.org/api/4.5/bpy_types_enum_items/property_flag_items.html#rna-enum-property-flag-items
option_path_supports_blend_relative = {'PATH_SUPPORTS_BLEND_RELATIVE'}
cache_directory = StringProperty(
cache_directory: StringProperty(
name="",
description="Simulation files will be saved to this directory."
" It is recommended to save your .blend file before beginning a simulation",
@@ -47,46 +44,46 @@ class DomainCacheProperties(bpy.types.PropertyGroup):
subtype='DIR_PATH',
options=option_path_supports_blend_relative,
update=lambda self, context: self._update_cache_directory(context),
); exec(conv("cache_directory"))
default_cache_directory = StringProperty(
)
default_cache_directory: StringProperty(
default=default_cache_directory_str,
subtype='DIR_PATH',
options=option_path_supports_blend_relative,
); exec(conv("default_cache_directory"))
move_cache_directory = StringProperty(
)
move_cache_directory: StringProperty(
name="",
description="Cache directory will be moved to this location",
default=temp_directory,
subtype='DIR_PATH',
options=option_path_supports_blend_relative,
); exec(conv("move_cache_directory"))
rename_cache_directory = StringProperty(
)
rename_cache_directory: StringProperty(
name="",
description="Cache directory will be renamed to this value",
default="untitled_flip_fluid_cache",
); exec(conv("rename_cache_directory"))
copy_cache_directory = StringProperty(
)
copy_cache_directory: StringProperty(
name="",
description="Cache directory contents will be copied to this location",
default=default_cache_directory_str,
subtype='DIR_PATH',
options=option_path_supports_blend_relative,
); exec(conv("copy_cache_directory"))
clear_cache_directory_logs = BoolProperty(
)
clear_cache_directory_logs: BoolProperty(
name="Clear log files",
description="Also delete log files when freeing cache directory",
default=False,
); exec(conv("clear_cache_directory_logs"))
clear_cache_directory_export = BoolProperty(
)
clear_cache_directory_export: BoolProperty(
name="Clear export files",
description="Also delete exported settings and objects when freeing cache directory",
default=False,
); exec(conv("clear_cache_directory_export"))
logfile_name = StringProperty(
)
logfile_name: StringProperty(
default=os.path.join(temp_directory, "flip_fluid_log.txt"),
subtype='FILE_NAME',
); exec(conv("logfile_name"))
linked_geometry_directory = StringProperty(
)
linked_geometry_directory: StringProperty(
name="",
description="select an existing cache directory. Link exported geometry data from another cache directory."
" Use if you want to re-use exported geometry that is located in another cache. Useful if you have a"
@@ -94,13 +91,9 @@ class DomainCacheProperties(bpy.types.PropertyGroup):
default="",
subtype='DIR_PATH',
options=option_path_supports_blend_relative,
); exec(conv("linked_geometry_directory"))
)
is_cache_directory_set = BoolProperty(default=False); exec(conv("is_cache_directory_set"))
cache_directory_expanded = BoolProperty(default=True); exec(conv("cache_directory_expanded"))
link_exported_geometry_expanded = BoolProperty(default=False); exec(conv("link_exported_geometry_expanded"))
cache_operators_expanded = BoolProperty(default=False); exec(conv("cache_operators_expanded"))
is_cache_directory_set: BoolProperty(default=False)
def register_preset_properties(self, registry, path):
@@ -49,11 +49,10 @@ _LOGGING_DISABLED_MESSAGE = "(Blend file logging disabled in host preferences)"
class VersionHistoryItem(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
blender_version = StringProperty(default="-1"); exec(conv("blender_version"))
flip_fluids_version = StringProperty(default="-1"); exec(conv("flip_fluids_version"))
flip_fluids_label = StringProperty(default="-1"); exec(conv("flip_fluids_label"))
operating_system = StringProperty(default="-1"); exec(conv("operating_system"))
blender_version: StringProperty(default="-1")
flip_fluids_version: StringProperty(default="-1")
flip_fluids_label: StringProperty(default="-1")
operating_system: StringProperty(default="-1")
def get_info_string(self):
@@ -61,9 +60,8 @@ class VersionHistoryItem(bpy.types.PropertyGroup):
class DomainDebugProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
display_simulation_grid = BoolProperty(
display_simulation_grid: BoolProperty(
name="Display Domain Grid",
description="Visualize the domain voxel grid in the 3D viewport."
" Try scaling different sides of the domain to better understand how the grid works."
@@ -71,15 +69,15 @@ class DomainDebugProperties(bpy.types.PropertyGroup):
" the differences in how the grid changes as the domain is resized",
default=False,
update=lambda self, context: self._update_display_simulation_grid(context),
); exec(conv("display_simulation_grid"))
grid_display_mode = EnumProperty(
)
grid_display_mode: EnumProperty(
name="Grid Display Mode",
description="Type of grid debug info to display",
items=types.grid_display_modes,
default='GRID_DISPLAY_SIMULATION',
update=lambda self, context: self._update_debug_grid_geometry(context),
); exec(conv("grid_display_mode"))
grid_display_scale = IntProperty(
)
grid_display_scale: IntProperty(
name="Grid Display Scale",
description="Number of voxels that a single grid spacing in the"
" viewport represents",
@@ -87,37 +85,37 @@ class DomainDebugProperties(bpy.types.PropertyGroup):
default=1,
step=1,
update=lambda self, context: self._update_debug_grid_geometry(context),
); exec(conv("grid_display_scale"))
enabled_debug_grids = BoolVectorProperty(
)
enabled_debug_grids: BoolVectorProperty(
name="Enabled Debug Grids",
description="Select which debug grids are displayed in the viewport",
default=(True, True, True),
size=3,
subtype='XYZ',
update=lambda self, context: self._update_debug_grid_geometry(context),
); exec(conv("enabled_debug_grids"))
x_grid_color = FloatVectorProperty(
)
x_grid_color: FloatVectorProperty(
name="X Grid Color",
subtype='COLOR',
default=(0.5, 0.0, 0.0),
min=0.0, max=1.0,
description="X grid display color"
); exec(conv("x_grid_color"))
y_grid_color = FloatVectorProperty(
)
y_grid_color: FloatVectorProperty(
name="Y Grid Color",
subtype='COLOR',
default=(0.0, 0.5, 0.0),
min=0.0, max=1.0,
description="Y grid display color"
); exec(conv("y_grid_color"))
z_grid_color = FloatVectorProperty(
)
z_grid_color: FloatVectorProperty(
name="Z Grid Color",
subtype='COLOR',
default=(0.0, 0.0, 0.5),
min=0.0, max=1.0,
description="Z grid display color"
); exec(conv("z_grid_color"))
debug_grid_offsets = FloatVectorProperty(
)
debug_grid_offsets: FloatVectorProperty(
name="Debug Grid Offsets",
description="Offset at which an axis' grid is displayed in the viewport",
min = 0.0, max = 1.0,
@@ -126,14 +124,14 @@ class DomainDebugProperties(bpy.types.PropertyGroup):
step=1,
subtype='XYZ',
update=lambda self, context: self._update_debug_grid_geometry(context),
); exec(conv("debug_grid_offsets"))
snap_offsets_to_grid = BoolProperty(
)
snap_offsets_to_grid: BoolProperty(
name="Snap Offsets to Grid",
description="Align debug grids to gridcell locations",
default=True,
update=lambda self, context: self._update_debug_grid_geometry(context),
); exec(conv("snap_offsets_to_grid"))
display_domain_bounds = BoolProperty(
)
display_domain_bounds: BoolProperty(
name="Display Bounds",
description="Display the true bounds of the domain object." +
" The domain boundary contains a thin solid layer. Enabling" +
@@ -141,154 +139,154 @@ class DomainDebugProperties(bpy.types.PropertyGroup):
" the domain",
default=False,
update=lambda self, context: self._update_display_domain_bounds(context),
); exec(conv("display_domain_bounds"))
domain_bounds_color = FloatVectorProperty(
)
domain_bounds_color: FloatVectorProperty(
name="Domain Bounds Color",
subtype='COLOR',
default=(1.0, 1.0, 0.0),
min=0.0, max=1.0,
description="Color of the domain bounds visualization",
update=lambda self, context: self._update_debug_grid_geometry(context),
); exec(conv("domain_bounds_color"))
)
enable_fluid_particle_debug_output = BoolProperty(
enable_fluid_particle_debug_output: BoolProperty(
name="Enable Fluid Particle Debugging",
description="Enable to export simulator fluid particle data and to"
" visualize and debug problems with fluid behaviour. Enable"
" this option before baking a simulation to use this feature",
default=False,
update=lambda self, context: self._update_enable_fluid_particle_debug_output(context),
); exec(conv("enable_fluid_particle_debug_output"))
fluid_particles_visibility = BoolProperty(
)
fluid_particles_visibility: BoolProperty(
name="Fluid Particle Visibility",
description="Show fluid particles in the viewport",
default=True,
update=lambda self, context: self._update_enable_fluid_particle_debug_output(context),
); exec(conv("fluid_particles_visibility"))
low_speed_particle_color = FloatVectorProperty(
)
low_speed_particle_color: FloatVectorProperty(
name="Low Speed Color",
subtype='COLOR',
default=(0.0, 0.0, 1.0),
min=0.0, max=1.0,
description="Color for low velocity fluid particles",
update=lambda self, context: self._update_debug_particle_geometry(context),
); exec(conv("low_speed_particle_color"))
high_speed_particle_color = FloatVectorProperty(
)
high_speed_particle_color: FloatVectorProperty(
name="High Speed Color",
subtype='COLOR',
default=(1.0, 1.0, 1.0),
min=0.0, max=1.0,
description="Color for high velocity fluid particles",
update=lambda self, context: self._update_debug_particle_geometry(context),
); exec(conv("high_speed_particle_color"))
min_gradient_speed = FloatProperty(
)
min_gradient_speed: FloatProperty(
name="Low Color Speed",
description="Low speed value for visualizing fluid particle velocity",
min=0,
default=0.0,
precision=2,
update=lambda self, context: self._update_min_gradient_speed(context),
); exec(conv("min_gradient_speed"))
max_gradient_speed = FloatProperty(
)
max_gradient_speed: FloatProperty(
name="High Color Speed",
description="High speed value for visualizing fluid particle velocity",
min=0,
default=5.0,
precision=2,
update=lambda self, context: self._update_max_gradient_speed(context),
); exec(conv("max_gradient_speed"))
fluid_particle_gradient_mode = EnumProperty(
)
fluid_particle_gradient_mode: EnumProperty(
name="Gradient Mode",
description="Type of color gradient",
items=types.gradient_interpolation_modes,
default='GRADIENT_RGB',
update=lambda self, context: self._update_max_gradient_speed(context),
); exec(conv("fluid_particle_gradient_mode"))
particle_size = IntProperty(
)
particle_size: IntProperty(
name="Particle Size",
description="Size to draw particles for visualization",
min=1, soft_max=10,
default=1,
update=lambda self, context: self._update_debug_particle_geometry(context),
); exec(conv("particle_size"))
particle_draw_aabb = PointerProperty(
)
particle_draw_aabb: PointerProperty(
name="Visualization Bounds",
description="If set, only particles inside the object's axis-aligned"
" bounding box will be drawn",
type=bpy.types.Object,
update=lambda self, context: self._update_debug_particle_geometry(context),
); exec(conv("particle_draw_aabb"))
)
export_force_field = BoolProperty(
export_force_field: BoolProperty(
name="Enable Force Field Debugging",
description="Enable to export simulator force field data and to"
" visualize force field lines. Enable this option before baking"
" a simulation to use this feature",
default=False,
update=lambda self, context: self._update_export_force_field(context),
); exec(conv("export_force_field"))
force_field_visibility = BoolProperty(
)
force_field_visibility: BoolProperty(
name="Force Field Visibility",
description="Show force fields in the viewport",
default=True,
update=lambda self, context: self._update_export_force_field(context),
); exec(conv("force_field_visibility"))
low_force_field_color = FloatVectorProperty(
)
low_force_field_color: FloatVectorProperty(
name="Low Force Color",
subtype='COLOR',
default=(1.0, 1.0, 1.0),
min=0.0, max=1.0,
description="Color for low strength forces",
update=lambda self, context: self._update_export_force_field(context),
); exec(conv("low_force_field_color"))
high_force_field_color = FloatVectorProperty(
)
high_force_field_color: FloatVectorProperty(
name="High Force Color",
subtype='COLOR',
default=(1.0, 0.0, 0.0),
min=0.0, max=1.0,
description="Color for high strength forces",
update=lambda self, context: self._update_export_force_field(context),
); exec(conv("high_force_field_color"))
min_gradient_force = FloatProperty(
)
min_gradient_force: FloatProperty(
name="Low Color Force",
description="Low force strength value for visualizing force field lines",
min=0,
default=0.0,
precision=2,
update=lambda self, context: self._update_min_gradient_force(context),
); exec(conv("min_gradient_force"))
max_gradient_force = FloatProperty(
)
max_gradient_force: FloatProperty(
name="High Color Force",
description="High force strength value for visualizing force field lines",
min=0,
default=15.0,
precision=2,
update=lambda self, context: self._update_max_gradient_force(context),
); exec(conv("max_gradient_force"))
force_field_gradient_mode = EnumProperty(
)
force_field_gradient_mode: EnumProperty(
name="Gradient Mode",
description="Type of color gradient",
items=types.gradient_interpolation_modes,
default='GRADIENT_RGB',
update=lambda self, context: self._update_max_gradient_force(context),
); exec(conv("force_field_gradient_mode"))
force_field_display_amount = IntProperty(
)
force_field_display_amount: IntProperty(
name="Display Amount",
description="Amount of force field lines to display in the viewport",
min=0, max=100,
default=25,
subtype='PERCENTAGE',
update=lambda self, context: self._update_force_field_geometry(context),
); exec(conv("force_field_display_amount"))
force_field_line_size = IntProperty(
)
force_field_line_size: IntProperty(
name="Line Size",
description="Line thickness for force field visualization",
min=1, soft_max=10,
default=2,
update=lambda self, context: self._update_force_field_geometry(context),
); exec(conv("force_field_line_size"))
)
export_internal_obstacle_mesh = BoolProperty(
export_internal_obstacle_mesh: BoolProperty(
name="Enable Obstacle Debugging",
description="Enable to export simulator obstacle data"
" and to visualize and debug problems with obstacles."
@@ -296,41 +294,37 @@ class DomainDebugProperties(bpy.types.PropertyGroup):
" use this feature",
default=False,
update=lambda self, context: self._update_export_internal_obstacle_mesh(context),
); exec(conv("export_internal_obstacle_mesh"))
internal_obstacle_mesh_visibility = BoolProperty(
)
internal_obstacle_mesh_visibility: BoolProperty(
name="Obstacle Debugging Visibility",
description="Show obstacle debug mesh in the viewport. If disabled, this prevents debug obstacle"
" mesh data from being loaded into Blender. Frame must be reloaded after enabling this option for"
" mesh to reload and become visible",
default=True,
update=lambda self, context: self._update_export_internal_obstacle_mesh(context),
); exec(conv("internal_obstacle_mesh_visibility"))
)
display_console_output = BoolProperty(
display_console_output: BoolProperty(
name="Display Console Output",
description="Display simulation info in the Blender system console",
default=True,
update=lambda self, context: self._update_display_console_output(context),
options={'HIDDEN'},
); exec(conv("display_console_output"))
)
display_render_passes_console_output = BoolProperty(
display_render_passes_console_output: BoolProperty(
name="Display Render Passes Console Output",
description="Display Compositing Tools Passes Rendering debug info in the Blender system console",
default=False,
options={'HIDDEN'},
); exec(conv("display_render_passes_console_output"))
)
is_draw_debug_grid_operator_running = BoolProperty(default=False); exec(conv("is_draw_debug_grid_operator_running"))
is_draw_gl_particles_operator_running = BoolProperty(default=False); exec(conv("is_draw_gl_particles_operator_running"))
is_draw_gl_force_field_operator_running = BoolProperty(default=False); exec(conv("is_draw_gl_force_field_operator_running"))
is_draw_debug_grid_operator_running: BoolProperty(default=False)
is_draw_gl_particles_operator_running: BoolProperty(default=False)
is_draw_gl_force_field_operator_running: BoolProperty(default=False)
grid_display_settings_expanded = BoolProperty(default=True); exec(conv("grid_display_settings_expanded"))
particle_debug_settings_expanded = BoolProperty(default=False); exec(conv("particle_debug_settings_expanded"))
force_field_debug_settings_expanded = BoolProperty(default=False); exec(conv("force_field_debug_settings_expanded"))
version_history = CollectionProperty(type=VersionHistoryItem); exec(conv("version_history"))
system_info = StringProperty(default=""); exec(conv("system_info"))
version_history: CollectionProperty(type=VersionHistoryItem)
system_info: StringProperty(default="")
def register_preset_properties(self, registry, path):
@@ -410,11 +404,7 @@ class DomainDebugProperties(bpy.types.PropertyGroup):
preferences = vcu.get_addon_preferences()
if preferences.enable_blend_file_logging:
# Save Version History
if vcu.is_blender_42():
bl_info_dict = bl_info
else:
bl_info_dict = sys.modules[installation_utils.get_module_name()].bl_info
bl_info_dict = bl_info
vdata = self.version_history.add()
vdata.blender_version = bpy.app.version_string
vdata.flip_fluids_version = str(bl_info_dict.get('version', (-1, -1, -1)))
@@ -27,24 +27,23 @@ from ..utils import version_compatibility_utils as vcu
class DomainMaterialsProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
surface_material = EnumProperty(
surface_material: EnumProperty(
name="Fluid Surface",
description="Select a material for the fluid surface. Tip: materials can also be"
" created and assigned to the fluid_surface object in Blender's Material"
" Properties panel",
items=material_library.get_surface_material_enums_ui,
update=lambda self, context: self._update_surface_material(context),
); exec(conv("surface_material"))
fluid_particles_material = EnumProperty(
)
fluid_particles_material: EnumProperty(
name="Fluid Particles",
description="Select a material for the fluid particles. Tip: If the object contains"
" a Point Cloud geometry node modifier, the material can be set in the modifier settings",
items=material_library.get_fluid_particles_material_enums_ui,
update=lambda self, context: self._update_fluid_particles_material(context),
); exec(conv("fluid_particles_material"))
whitewater_foam_material = EnumProperty(
)
whitewater_foam_material: EnumProperty(
name="Whitewater Foam",
description="Select a material for the foam particles. Tip: materials can also be"
" created and assigned to the whitewater_foam object in Blender's Material"
@@ -52,8 +51,8 @@ class DomainMaterialsProperties(bpy.types.PropertyGroup):
" the material can be set in the modifier settings",
items=material_library.get_whitewater_material_enums_ui,
update=lambda self, context: self._update_whitewater_foam_material(context),
); exec(conv("whitewater_foam_material"))
whitewater_bubble_material = EnumProperty(
)
whitewater_bubble_material: EnumProperty(
name="Whitewater Bubble",
description="Select a material for the bubble particles. Tip: materials can also be"
" created and assigned to the whitewater_bubble object in Blender's Material"
@@ -61,8 +60,8 @@ class DomainMaterialsProperties(bpy.types.PropertyGroup):
" the material can be set in the modifier settings",
items=material_library.get_whitewater_material_enums_ui,
update=lambda self, context: self._update_whitewater_bubble_material(context),
); exec(conv("whitewater_bubble_material"))
whitewater_spray_material = EnumProperty(
)
whitewater_spray_material: EnumProperty(
name="Whitewater Spray",
description="Select a material for the spray particles. Tip: materials can also be"
" created and assigned to the whitewater_spray object in Blender's Material"
@@ -70,8 +69,8 @@ class DomainMaterialsProperties(bpy.types.PropertyGroup):
" the material can be set in the modifier settings",
items=material_library.get_whitewater_material_enums_ui,
update=lambda self, context: self._update_whitewater_spray_material(context),
); exec(conv("whitewater_spray_material"))
whitewater_dust_material = EnumProperty(
)
whitewater_dust_material: EnumProperty(
name="Whitewater Dust",
description="Select a material for the dust particles. Tip: materials can also be"
" created and assigned to the whitewater_dust object in Blender's Material"
@@ -79,19 +78,19 @@ class DomainMaterialsProperties(bpy.types.PropertyGroup):
" the material can be set in the modifier settings",
items=material_library.get_whitewater_material_enums_ui,
update=lambda self, context: self._update_whitewater_dust_material(context),
); exec(conv("whitewater_dust_material"))
material_import = EnumProperty(
)
material_import: EnumProperty(
name="Import",
description="Import materials into this scene",
items=material_library.get_material_import_enums_ui,
); exec(conv("material_import"))
)
last_surface_material = StringProperty(default=""); exec(conv("last_surface_material"))
last_fluid_particles_material = StringProperty(default=""); exec(conv("last_fluid_particles_material"))
last_whitewater_foam_material = StringProperty(default=""); exec(conv("last_whitewater_foam_material"))
last_whitewater_bubble_material = StringProperty(default=""); exec(conv("last_whitewater_bubble_material"))
last_whitewater_spray_material = StringProperty(default=""); exec(conv("last_whitewater_spray_material"))
last_whitewater_dust_material = StringProperty(default=""); exec(conv("last_whitewater_dust_material"))
last_surface_material: StringProperty(default="")
last_fluid_particles_material: StringProperty(default="")
last_whitewater_foam_material: StringProperty(default="")
last_whitewater_bubble_material: StringProperty(default="")
last_whitewater_spray_material: StringProperty(default="")
last_whitewater_dust_material: StringProperty(default="")
def load_post(self):
@@ -28,16 +28,15 @@ from ..utils import version_compatibility_utils as vcu
class DomainParticlesProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
enable_fluid_particle_output = BoolProperty(
enable_fluid_particle_output: BoolProperty(
name="Enable Fluid Particle Export",
description="Enable fluid particle data to be exported to the simulation cache",
default=False,
update=lambda self, context: self._update_enable_fluid_particle_output(context),
options={'HIDDEN'},
); exec(conv("enable_fluid_particle_output"))
fluid_particle_output_amount = FloatProperty(
)
fluid_particle_output_amount: FloatProperty(
name="Particle Export Amount",
description="Amount of fluid particles to export. A value of 1.0 will export all fluid particles."
" Decrease this value to reduce cache size if not all particles will need to be displayed or"
@@ -48,36 +47,36 @@ class DomainParticlesProperties(bpy.types.PropertyGroup):
precision=5,
subtype='FACTOR',
options={'HIDDEN'},
); exec(conv("fluid_particle_output_amount"))
enable_fluid_particle_surface_output = BoolProperty(
)
enable_fluid_particle_surface_output: BoolProperty(
name="Export Surface Particles",
description="Export fluid particles near the fluid surface. Particles are considered"
" to be surface particles if they are near empty air, but are not near the domain boundary",
default=True,
); exec(conv("enable_fluid_particle_surface_output"))
enable_fluid_particle_boundary_output = BoolProperty(
)
enable_fluid_particle_boundary_output: BoolProperty(
name="Export Boundary Particles",
description="Export fluid particles near the domain boundary. Particles are considered to"
" be boundary particles if they are near the boundary of the domain. If a surface"
" Meshing Volume object is set, particles near the surface of this object are considered"
" boundary particles",
default=True,
); exec(conv("enable_fluid_particle_boundary_output"))
enable_fluid_particle_interior_output = BoolProperty(
)
enable_fluid_particle_interior_output: BoolProperty(
name="Export Interior Particles",
description="Export fluid particles inside of the fluid surface. Particles are considered"
" to be interior particles if they are not classified as either surface or boundary particles",
default=True,
); exec(conv("enable_fluid_particle_interior_output"))
fluid_particle_source_id_blacklist = IntProperty(
)
fluid_particle_source_id_blacklist: IntProperty(
name="Skip Source ID",
description="If the Source ID attribute is enabled, do not export fluid particles with the specified"
" Source ID value. Useful to reduce cache size and speed up playback in situations where particles"
" are not needed from specific Fluid or Inflow objects",
min=-1,
default=-1,
); exec(conv("fluid_particle_source_id_blacklist"))
enable_fluid_particle_velocity_vector_attribute = BoolProperty(
)
enable_fluid_particle_velocity_vector_attribute: BoolProperty(
name="Generate Velocity Attributes",
description="Generate fluid 3D velocity vector attributes for the fluid particles. After"
" baking, the velocity vectors (in m/s) can be accessed in a Cycles Attribute"
@@ -86,24 +85,24 @@ class DomainParticlesProperties(bpy.types.PropertyGroup):
" direction is not needed, use Generate Speed Attributes instead",
default=False,
options={'HIDDEN'},
); exec(conv("enable_fluid_particle_velocity_vector_attribute"))
enable_fluid_particle_speed_attribute = BoolProperty(
)
enable_fluid_particle_speed_attribute: BoolProperty(
name="Generate Speed Attributes",
description="Generate fluid speed attributes for the fluid particles. After"
" baking, the speed values (in m/s) can be accessed in a Cycles Attribute"
" Node or in Geometry Nodes with the name 'flip_speed' from the Fac output",
default=False,
options={'HIDDEN'},
); exec(conv("enable_fluid_particle_speed_attribute"))
enable_fluid_particle_vorticity_vector_attribute = BoolProperty(
)
enable_fluid_particle_vorticity_vector_attribute: BoolProperty(
name="Generate Vorticity Attributes",
description="Generate fluid 3D vorticity vector attributes for the fluid particles. After"
" baking, the vorticity vectors can be accessed in a Cycles Attribute"
" Node or in Geometry Nodes with the name 'flip_vorticity' from the Vector output",
default=False,
options={'HIDDEN'},
); exec(conv("enable_fluid_particle_vorticity_vector_attribute"))
enable_fluid_particle_color_attribute = BoolProperty(
)
enable_fluid_particle_color_attribute: BoolProperty(
name="Generate Color Attributes",
description="Generate fluid color attributes for the fluid particles. Each"
" Inflow/Fluid object can set to assign color to the generated fluid. After"
@@ -112,8 +111,8 @@ class DomainParticlesProperties(bpy.types.PropertyGroup):
" liquid effects",
default=False,
options={'HIDDEN'},
); exec(conv("enable_fluid_particle_color_attribute"))
enable_fluid_particle_age_attribute = BoolProperty(
)
enable_fluid_particle_age_attribute: BoolProperty(
name="Generate Age Attributes",
description="Generate fluid age attributes for the fluid particles."
" The age attribute starts at 0.0 when the liquid is spawned and counts up in"
@@ -121,8 +120,8 @@ class DomainParticlesProperties(bpy.types.PropertyGroup):
" Node or in Geometry Nodes with the name 'flip_age' from the Fac output",
default=False,
options={'HIDDEN'},
); exec(conv("enable_fluid_particle_age_attribute"))
enable_fluid_particle_lifetime_attribute = BoolProperty(
)
enable_fluid_particle_lifetime_attribute: BoolProperty(
name="Generate Lifetime Attributes",
description="Generate fluid lifetime attributes for the fluid particles. This attribute allows the"
" fluid to start with a lifetime value that counts down in seconds and once the lifetime reaches 0,"
@@ -132,8 +131,8 @@ class DomainParticlesProperties(bpy.types.PropertyGroup):
" the Fac output",
default=False,
options={'HIDDEN'},
); exec(conv("enable_fluid_particle_lifetime_attribute"))
enable_fluid_particle_whitewater_proximity_attribute = BoolProperty(
)
enable_fluid_particle_whitewater_proximity_attribute: BoolProperty(
name="Generate Whitewater Proximity Attributes",
description="Generate whitewater proximity attributes for the fluid particles. The attribute values represent"
" how many foam, bubble, or spray particles are near a fluid particle and can be used in a material to shade"
@@ -142,8 +141,8 @@ class DomainParticlesProperties(bpy.types.PropertyGroup):
" and 'flip_spray_proximity' from the Fac output",
default=False,
options={'HIDDEN'},
); exec(conv("enable_fluid_particle_whitewater_proximity_attribute"))
enable_fluid_particle_source_id_attribute = BoolProperty(
)
enable_fluid_particle_source_id_attribute: BoolProperty(
name="Generate Source ID Attributes",
description="Generate fluid source identifiers for the fluid particles. Each"
" Inflow/Fluid object can set to assign a source ID to the generated particles. After"
@@ -153,8 +152,8 @@ class DomainParticlesProperties(bpy.types.PropertyGroup):
" not supported with sheeting effects or resolution upscaling features",
default=False,
options={'HIDDEN'},
); exec(conv("enable_fluid_particle_source_id_attribute"))
enable_fluid_particle_uid_attribute = BoolProperty(
)
enable_fluid_particle_uid_attribute: BoolProperty(
name="Generate UID Attributes",
description="Generate Unique IDs for fluid particles. After"
" baking, the UID values can be accessed in a Cycles Attribute Node or in Geometry nodes with the name"
@@ -164,8 +163,8 @@ class DomainParticlesProperties(bpy.types.PropertyGroup):
" leave this attribute disabled",
default=False,
options={'HIDDEN'},
); exec(conv("enable_fluid_particle_uid_attribute"))
enable_fluid_particle_uid_attribute_reuse = BoolProperty(
)
enable_fluid_particle_uid_attribute_reuse: BoolProperty(
name="Reuse UIDs",
description="Reuse UID attribute values. If enabled, particles that are removed from the simulation may have"
" their UID reused in a later frame. If a particle is removed from the simulation, the UID will not be"
@@ -175,15 +174,7 @@ class DomainParticlesProperties(bpy.types.PropertyGroup):
" in geometry nodes",
default=True,
options={'HIDDEN'},
); exec(conv("enable_fluid_particle_uid_attribute_reuse"))
fluid_particles_expanded = BoolProperty(default=True); exec(conv("fluid_particles_expanded"))
fluid_particle_generation_expanded = BoolProperty(default=False); exec(conv("fluid_particle_generation_expanded"))
fluid_particle_display_settings_expanded = BoolProperty(default=False); exec(conv("fluid_particle_display_settings_expanded"))
geometry_attributes_expanded = BoolProperty(default=False); exec(conv("geometry_attributes_expanded"))
velocity_attributes_expanded = BoolProperty(default=False); exec(conv("velocity_attributes_expanded"))
color_attributes_expanded = BoolProperty(default=False); exec(conv("color_attributes_expanded"))
other_attributes_expanded = BoolProperty(default=False); exec(conv("other_attributes_expanded"))
)
def register_preset_properties(self, registry, path):
@@ -30,81 +30,79 @@ from ..utils import version_compatibility_utils as vcu
class DomainPresetsProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
enable_presets = BoolProperty(
enable_presets: BoolProperty(
name="Enable Presets",
description="Enable functionality to apply fluid presets",
default=False,
update=lambda self, context: self._update_enable_presets(context),
); exec(conv("enable_presets"))
current_package = EnumProperty(
)
current_package: EnumProperty(
name="Package",
description="Preset package",
items=preset_library.get_all_package_enums,
update=lambda self, context: self._update_current_package(context),
); exec(conv("current_package"))
current_preset = EnumProperty(
)
current_preset: EnumProperty(
items=preset_library.get_current_package_preset_enums,
name="Preset",
description="Fluid Preset",
update=lambda self, context: self._update_current_preset(context),
); exec(conv("current_preset"))
preview_preset = BoolProperty(
)
preview_preset: BoolProperty(
name="Preview",
description="Automatically assign preset on change (without"
" needing to add to the preset stack)",
default=False,
update=lambda self, context: self._update_preview_preset(context),
); exec(conv("preview_preset"))
new_package_settings = PointerProperty(
)
new_package_settings: PointerProperty(
name="New Package Settings",
description="",
type=preset_properties.NewPresetPackageSettings,
); exec(conv("new_package_settings"))
delete_package_settings = PointerProperty(
)
delete_package_settings: PointerProperty(
name="Delete Package Settings",
description="",
type=preset_properties.DeletePresetPackageSettings,
); exec(conv("delete_package_settings"))
new_preset_settings = PointerProperty(
)
new_preset_settings: PointerProperty(
name="New Preset Settings",
description="",
type=preset_properties.NewPresetSettings,
); exec(conv("new_preset_settings"))
delete_preset_settings = PointerProperty(
)
delete_preset_settings: PointerProperty(
name="Delete Preset Settings",
description="",
type=preset_properties.DeletePresetSettings,
); exec(conv("delete_preset_settings"))
edit_preset_settings = PointerProperty(
)
edit_preset_settings: PointerProperty(
name="Edit Preset Settings",
description="",
type=preset_properties.EditPresetSettings,
); exec(conv("edit_preset_settings"))
display_preset_settings = PointerProperty(
)
display_preset_settings: PointerProperty(
name="Display Preset Settings",
description="",
type=preset_properties.DisplayPresetInfoSettings,
); exec(conv("display_preset_settings"))
export_package_settings = PointerProperty(
)
export_package_settings: PointerProperty(
name="Export Package Settings",
description="",
type=preset_properties.ExportPresetPackageSettings,
); exec(conv("export_package_settings"))
import_package_settings = PointerProperty(
)
import_package_settings: PointerProperty(
name="Import Package Settings",
description="",
type=preset_properties.ImportPresetPackageSettings,
); exec(conv("import_package_settings"))
preset_stack = PointerProperty(
)
preset_stack: PointerProperty(
name="Flip Fluid Preset Stack",
description="",
type=flip_fluid_preset_stack.FlipFluidPresetStack,
); exec(conv("preset_stack"))
preset_manager_expanded = BoolProperty(default=False); exec(conv("preset_manager_expanded"))
deprecated_presets_disabled_on_load = BoolProperty(default=False); exec(conv("deprecated_presets_disabled_on_load"))
)
deprecated_presets_disabled_on_load: BoolProperty(default=False)
def register_preset_properties(self, registry, path):
@@ -70,97 +70,94 @@ from ..utils import api_workaround_utils
class FlipFluidDomainProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
render = PointerProperty(
render: PointerProperty(
name="Domain Render Properties",
description="",
type=domain_render_properties.DomainRenderProperties,
); exec(conv("render"))
bake = PointerProperty(
)
bake: PointerProperty(
name="Domain Bake Properties",
description="",
type=domain_bake_properties.DomainBakeProperties,
); exec(conv("bake"))
simulation = PointerProperty(
)
simulation: PointerProperty(
name="Domain Simulation Properties",
description="",
type=domain_simulation_properties.DomainSimulationProperties,
); exec(conv("simulation"))
cache = PointerProperty(
)
cache: PointerProperty(
name="Domain Cache Properties",
description="",
type=domain_cache_properties.DomainCacheProperties,
); exec(conv("cache"))
particles = PointerProperty(
)
particles: PointerProperty(
name="Domain Surface Properties",
description="",
type=domain_particles_properties.DomainParticlesProperties,
); exec(conv("particles"))
surface = PointerProperty(
)
surface: PointerProperty(
name="Domain Surface Properties",
description="",
type=domain_surface_properties.DomainSurfaceProperties,
); exec(conv("surface"))
whitewater = PointerProperty(
)
whitewater: PointerProperty(
name="Domain Whitewater Properties",
description="",
type=domain_whitewater_properties.DomainWhitewaterProperties,
); exec(conv("whitewater"))
world = PointerProperty(
)
world: PointerProperty(
name="Domain World Properties",
description="",
type=domain_world_properties.DomainWorldProperties,
); exec(conv("world"))
presets = PointerProperty(
)
presets: PointerProperty(
name="Domain Presets Properties",
description="",
type=domain_presets_properties.DomainPresetsProperties,
); exec(conv("presets"))
materials = PointerProperty(
)
materials: PointerProperty(
name="Domain Materials Properties",
description="",
type=domain_materials_properties.DomainMaterialsProperties,
); exec(conv("materials"))
advanced = PointerProperty(
)
advanced: PointerProperty(
name="Domain Advanced Properties",
description="",
type=domain_advanced_properties.DomainAdvancedProperties,
); exec(conv("advanced"))
debug = PointerProperty(
)
debug: PointerProperty(
name="Domain Debug Properties",
description="",
type=domain_debug_properties.DomainDebugProperties,
); exec(conv("debug"))
stats = PointerProperty(
)
stats: PointerProperty(
name="Domain Stats Properties",
description="",
type=domain_stats_properties.DomainStatsProperties,
); exec(conv("stats"))
mesh_cache = PointerProperty(
)
mesh_cache: PointerProperty(
name="Domain Mesh Cache",
description="",
type=flip_fluid_cache.FlipFluidCache,
); exec(conv("mesh_cache"))
property_registry = PointerProperty(
)
property_registry: PointerProperty(
name="Domain Property Registry",
description="",
type=preset_properties.PresetRegistry,
); exec(conv("property_registry"))
)
domain_settings_tabbed_panel_view = EnumProperty(
domain_settings_tabbed_panel_view: EnumProperty(
name="Domain Panel View",
description="Select settings panel to display",
items=types.domain_settings_panel,
default='DOMAIN_SETTINGS_PANEL_SIMULATION',
options={'HIDDEN'},
); exec(conv("domain_settings_tabbed_panel_view"))
)
is_updated_to_flip_fluids_version_180 = BoolProperty(default=False)
exec(conv("is_updated_to_flip_fluids_version_180"));
is_updated_to_flip_fluids_version_184 = BoolProperty(default=False)
exec(conv("is_updated_to_flip_fluids_version_184"));
is_updated_to_flip_fluids_version_180: BoolProperty(default=False)
is_updated_to_flip_fluids_version_184: BoolProperty(default=False)
is_updated_to_flip_fluids_version_185: BoolProperty(default=False)
def initialize(self):
@@ -443,6 +440,28 @@ class FlipFluidDomainProperties(bpy.types.PropertyGroup):
self.is_updated_to_flip_fluids_version_184 = True
def _update_to_flip_fluids_version_185(self):
dprops = bpy.context.scene.flip_fluid.get_domain_properties()
if dprops is None:
return
if self.is_updated_to_flip_fluids_version_185:
return
print("\n*** Begin updating FLIP Domain to FLIP Fluids version 1.8.5+ ***")
parent_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
blend_resource_filename = "geometry_nodes_library.blend"
resource_filepath = os.path.join(parent_path, "resources", "geometry_nodes", blend_resource_filename)
# Fluid surface should now always have a FF_GeometryNodesSurface modifier
mesh_cache_surface = dprops.mesh_cache.surface.get_cache_object()
gn_modifier = helper_operators.add_geometry_node_modifier(mesh_cache_surface, resource_filepath, "FF_GeometryNodesSurface")
print("*** Finished updating FLIP Domain to FLIP Fluids version 1.8.5+ ***\n")
self.is_updated_to_flip_fluids_version_185 = True
def scene_update_post(self, scene):
self.render.scene_update_post(scene)
self.simulation.scene_update_post(scene)
@@ -479,6 +498,7 @@ class FlipFluidDomainProperties(bpy.types.PropertyGroup):
api_workaround_utils.load_post_update_cycles_visibility_forward_compatibility_from_blender_3()
self._update_to_flip_fluids_version_180()
self._update_to_flip_fluids_version_184()
self._update_to_flip_fluids_version_185()
def save_pre(self):
@@ -33,21 +33,20 @@ def object_is_mesh_type_poll(self, obj):
class DomainRenderProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
render_display = EnumProperty(
render_display: EnumProperty(
name="Render Display Mode",
description="How to display the surface mesh for rendering",
items=types.display_modes,
default='DISPLAY_FINAL',
); exec(conv("render_display"))
viewport_display = EnumProperty(
)
viewport_display: EnumProperty(
name="Viewport Display Mode",
description="How to display the surface mesh in the viewport",
items=types.display_modes,
default='DISPLAY_FINAL',
); exec(conv("viewport_display"))
render_surface_motion_blur = BoolProperty(
)
render_surface_motion_blur: BoolProperty(
name="Render Motion Blur",
description="Enable surface motion blur rendering. Motion blur"
" vectors must be generated to render motion blur. See"
@@ -55,8 +54,8 @@ class DomainRenderProperties(bpy.types.PropertyGroup):
" Motion blur must also be enabled in the Cycles render"
" properties",
default=True,
); exec(conv("render_surface_motion_blur"))
surface_motion_blur_scale = FloatProperty(
)
surface_motion_blur_scale: FloatProperty(
name="Scale",
description="Scale of the surface motion blur vectors. Increasing this"
" value will increase the amount of motion blur. Negative"
@@ -65,22 +64,22 @@ class DomainRenderProperties(bpy.types.PropertyGroup):
min=-10.0, max=10.0,
step=0.1,
precision=3,
); exec(conv("surface_motion_blur_scale"))
)
fluid_particle_render_display = EnumProperty(
fluid_particle_render_display: EnumProperty(
name="Fluid Particle Render Display Mode",
description="How to display the fluid particles for rendering",
items=types.display_modes,
default='DISPLAY_FINAL',
); exec(conv("fluid_particle_render_display"))
fluid_particle_viewport_display = EnumProperty(
)
fluid_particle_viewport_display: EnumProperty(
name="Whitewater Viewport Display Mode",
description="How to display the fluid particles in the viewport",
items=types.display_modes,
default='DISPLAY_PREVIEW',
); exec(conv("fluid_particle_viewport_display"))
render_fluid_particle_surface_pct = FloatProperty(
)
render_fluid_particle_surface_pct: FloatProperty(
name="Surface",
description="Amount of total surface fluid particles to display during render. Surface"
" particles are near the fluid surface and border empty air, but are not near"
@@ -88,16 +87,16 @@ class DomainRenderProperties(bpy.types.PropertyGroup):
min=0.0, max=1.0,
default=1.0,
precision=5,
); exec(conv("render_fluid_particle_surface_pct"))
render_fluid_particle_boundary_pct = FloatProperty(
)
render_fluid_particle_boundary_pct: FloatProperty(
name="Boundary",
description="Amount of total boundary fluid particles to display during render. Boundary"
" particles are located near the domain boundary",
min=0.0, max=1.0,
default=1.0,
precision=5,
); exec(conv("render_fluid_particle_boundary_pct"))
render_fluid_particle_interior_pct = FloatProperty(
)
render_fluid_particle_interior_pct: FloatProperty(
name="Interior",
description="Amount of total interior fluid particles to display during render. Interior"
" particles are within the fluid and are particles that have not been classified"
@@ -105,48 +104,48 @@ class DomainRenderProperties(bpy.types.PropertyGroup):
min=0.0, max=1.0,
default=1.0,
precision=5,
); exec(conv("render_fluid_particle_interior_pct"))
viewport_fluid_particle_surface_pct = FloatProperty(
)
viewport_fluid_particle_surface_pct: FloatProperty(
name="Surface",
description="Amount of total surface fluid particles to display in the viewport. Surface"
" particles are near the fluid surface or obstacles, but are not near"
" the domain boundary",
min=0.0, max=1.0,
default=0.5,
default=0.1,
precision=5,
); exec(conv("viewport_fluid_particle_surface_pct"))
viewport_fluid_particle_boundary_pct = FloatProperty(
)
viewport_fluid_particle_boundary_pct: FloatProperty(
name="Boundary",
description="Amount of total boundary fluid particles to display in the viewport. Boundary"
" particles are located near the domain boundary",
min=0.0, max=1.0,
default=0.25,
default=0.1,
precision=5,
); exec(conv("viewport_fluid_particle_boundary_pct"))
viewport_fluid_particle_interior_pct = FloatProperty(
)
viewport_fluid_particle_interior_pct: FloatProperty(
name="Interior",
description="Amount of total interior fluid particles to display in the viewport. Interior"
" particles are within the fluid and are particles that have not been classified"
" as either surface or boundary particles ",
min=0.0, max=1.0,
default=0.05,
default=0.1,
precision=5,
); exec(conv("viewport_fluid_particle_interior_pct"))
)
whitewater_render_display = EnumProperty(
whitewater_render_display: EnumProperty(
name="Whitewater Render Display Mode",
description="How to display the whitewater particles for rendering",
items=types.display_modes,
default='DISPLAY_FINAL',
); exec(conv("whitewater_render_display"))
whitewater_viewport_display = EnumProperty(
)
whitewater_viewport_display: EnumProperty(
name="Whitewater Viewport Display Mode",
description="How to display the whitewater particles in the viewport",
items=types.display_modes,
default='DISPLAY_FINAL',
); exec(conv("whitewater_viewport_display"))
render_whitewater_motion_blur = BoolProperty(
)
render_whitewater_motion_blur: BoolProperty(
name="Render Motion Blur",
description="Enable whitewater motion blur rendering. Motion blur"
" vectors must be generated to render motion blur. See"
@@ -154,8 +153,8 @@ class DomainRenderProperties(bpy.types.PropertyGroup):
" Motion blur must also be enabled in the Cycles render"
" properties",
default=True,
); exec(conv("render_whitewater_motion_blur"))
whitewater_motion_blur_scale = FloatProperty(
)
whitewater_motion_blur_scale: FloatProperty(
name="Scale",
description="Scale of the whitewater motion blur vectors. Increasing this"
" value will increase the amount of motion blur. Negative"
@@ -164,163 +163,158 @@ class DomainRenderProperties(bpy.types.PropertyGroup):
min=-10.0, max=10.0,
step=0.1,
precision=3,
); exec(conv("whitewater_motion_blur_scale"))
render_whitewater_pct = IntProperty(
)
render_whitewater_pct: IntProperty(
name="Whitewater",
description="Percentage of total whitewater particles to display",
min=0, max=100,
default=100,
subtype='PERCENTAGE',
); exec(conv("render_whitewater_pct"))
render_foam_pct = IntProperty(
)
render_foam_pct: IntProperty(
name="Foam",
description="Percentage of total foam particles to display",
min=0, max=100,
default=100,
subtype='PERCENTAGE',
); exec(conv("render_foam_pct"))
render_bubble_pct = IntProperty(
)
render_bubble_pct: IntProperty(
name="Bubble",
description="Percentage of total bubble particles to display",
min=0, max=100,
default=100,
subtype='PERCENTAGE',
); exec(conv("render_bubble_pct"))
render_spray_pct = IntProperty(
)
render_spray_pct: IntProperty(
name="Spray",
description="Percentage of total spray particles to display",
min=0, max=100,
default=100,
subtype='PERCENTAGE',
); exec(conv("render_spray_pct"))
render_dust_pct = IntProperty(
)
render_dust_pct: IntProperty(
name="Dust",
description="Percentage of total dust particles to display",
min=0, max=100,
default=100,
subtype='PERCENTAGE',
); exec(conv("render_dust_pct"))
viewport_whitewater_pct = IntProperty(
)
viewport_whitewater_pct: IntProperty(
name="Whitewater",
description="Percentage of total whitewater particles to display",
min=0, max=100,
default=5,
subtype='PERCENTAGE',
); exec(conv("viewport_whitewater_pct"))
viewport_foam_pct = IntProperty(
)
viewport_foam_pct: IntProperty(
name="Foam",
description="Percentage of total foam particles to display",
min=0, max=100,
default=5,
subtype='PERCENTAGE',
); exec(conv("viewport_foam_pct"))
viewport_bubble_pct = IntProperty(
)
viewport_bubble_pct: IntProperty(
name="Bubble",
description="Percentage of total bubble particles to display",
min=0, max=100,
default=5,
subtype='PERCENTAGE',
); exec(conv("viewport_bubble_pct"))
viewport_spray_pct = IntProperty(
)
viewport_spray_pct: IntProperty(
name="Spray",
description="Percentage of total spray particles to display",
min=0, max=100,
default=5,
subtype='PERCENTAGE',
); exec(conv("viewport_spray_pct"))
viewport_dust_pct = IntProperty(
)
viewport_dust_pct: IntProperty(
name="Dust",
description="Percentage of total dust particles to display",
min=0, max=100,
default=5,
subtype='PERCENTAGE',
); exec(conv("viewport_dust_pct"))
)
whitewater_view_settings_mode = EnumProperty(
whitewater_view_settings_mode: EnumProperty(
name="View Settings Mode",
description="How display settings will be applied to whitewater particles",
items=types.whitewater_view_settings_modes,
default='VIEW_SETTINGS_WHITEWATER',
); exec(conv("whitewater_view_settings_mode"))
whitewater_particle_object_settings_mode = EnumProperty(
)
whitewater_particle_object_settings_mode: EnumProperty(
name="Particle Object Settings Mode",
description="How particle object settings will be applied to whitewater particles",
items=types.whitewater_object_settings_modes,
default='WHITEWATER_OBJECT_SETTINGS_WHITEWATER',
); exec(conv("whitewater_particle_object_settings_mode"))
)
# Particle scale settings are no longer used in FLIP Fluids 1.8.0+
# Only used to update Blend files created in FLIP Fluids 1.7.5 and earlier
# to newer addon versions.
whitewater_particle_scale = FloatProperty(
whitewater_particle_scale: FloatProperty(
name="Scale",
description="Scale of the whitewater particle object",
min=0.0,
default=0.008,
step=0.01,
precision=4,
); exec(conv("whitewater_particle_scale"))
foam_particle_scale = FloatProperty(
)
foam_particle_scale: FloatProperty(
name="Scale",
description="Scale of the foam particle object",
min=0.0,
default=0.008,
step=0.01,
precision=4,
); exec(conv("foam_particle_scale"))
bubble_particle_scale = FloatProperty(
)
bubble_particle_scale: FloatProperty(
name="Scale",
description="Scale of the bubble particle object",
min=0.0,
default=0.008,
step=0.01,
precision=4,
); exec(conv("bubble_particle_scale"))
spray_particle_scale = FloatProperty(
)
spray_particle_scale: FloatProperty(
name="Scale",
description="Scale of the spray particle object",
min=0.0,
default=0.008,
step=0.01,
precision=4,
); exec(conv("spray_particle_scale"))
dust_particle_scale = FloatProperty(
)
dust_particle_scale: FloatProperty(
name="Scale",
description="Scale of the dust particle object",
min=0.0,
default=0.008,
step=0.01,
precision=4,
); exec(conv("dust_particle_scale"))
)
simulation_playback_mode = EnumProperty(
simulation_playback_mode: EnumProperty(
name="Simulation Playback Mode",
description="How to playback the simulation animation",
items=types.simulation_playback_mode,
default='PLAYBACK_MODE_TIMELINE',
); exec(conv("simulation_playback_mode"))
override_frame = FloatProperty(
)
override_frame: FloatProperty(
name="Override Frame",
description="The custom frame number to override. If this value is not a whole number,"
" the frame to be loaded will be rounded down. TIP: This value can be keyframed for"
" complex control of simulation playback",
default=1.000,
); exec(conv("override_frame"))
hold_frame_number = IntProperty(
)
hold_frame_number: IntProperty(
name="Hold Frame",
description="Frame number to be held in place",
min=0,
default=0,
options = {'HIDDEN'},
); exec(conv("hold_frame_number"))
)
whitewater_display_settings_expanded = BoolProperty(default=False); exec(conv("whitewater_display_settings_expanded"))
fluid_particle_display_settings_expanded = BoolProperty(default=False); exec(conv("fluid_particle_display_settings_expanded"))
surface_display_settings_expanded = BoolProperty(default=True); exec(conv("surface_display_settings_expanded"))
simulation_display_settings_expanded = BoolProperty(default=False); exec(conv("simulation_display_settings_expanded"))
current_frame = IntProperty(default=-1); exec(conv("current_frame"))
is_hold_frame_number_set = BoolProperty(default=False); exec(conv("is_hold_frame_number_set"))
current_frame: IntProperty(default=-1)
is_hold_frame_number_set: BoolProperty(default=False)
def register_preset_properties(self, registry, path):
@@ -36,16 +36,15 @@ from ..utils import export_utils
class DomainSimulationProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
frame_range_mode = EnumProperty(
frame_range_mode: EnumProperty(
name="Frame Range Mode",
description="Frame range to use for baking the simulation",
items=types.frame_range_modes,
default='FRAME_RANGE_TIMELINE',
options={'HIDDEN'},
); exec(conv("frame_range_mode"))
frame_range_custom = NewMinMaxIntProperty(
)
frame_range_custom: NewMinMaxIntProperty(
name_min="Start Frame",
description_min="First frame of the simulation cache",
min_min=0,
@@ -57,63 +56,63 @@ class DomainSimulationProperties(bpy.types.PropertyGroup):
min_max=0,
default_max=250,
options_max={'HIDDEN'},
); exec(conv("frame_range_custom"))
update_settings_on_resume = BoolProperty(
)
update_settings_on_resume: BoolProperty(
name="Update Settings on Resume",
description="Update simulation settings and meshes when resuming a bake."
" If disabled, the simulator will use the original settings and meshes"
" from when the bake was started",
default=True,
options={'HIDDEN'},
); exec(conv("update_settings_on_resume"))
mesh_reexport_type_filter = EnumProperty(
)
mesh_reexport_type_filter: EnumProperty(
name="Object Motion Type",
description="Filter objects by motion type for skip re-export list display",
items=types.motion_filter_types,
default='MOTION_FILTER_TYPE_ANIMATED',
); exec(conv("mesh_reexport_type_filter"))
enable_savestates = BoolProperty(
)
enable_savestates: BoolProperty(
name="Enable Savestates",
description="Generate savestates/checkpoints as the simulation progresses."
" Savestates will allow you to rollback the simulation to an earlier"
" point so that you can re-simulate from a previous frame",
default=True,
options = {'HIDDEN'},
); exec(conv("enable_savestates"))
savestate_interval = IntProperty(
)
savestate_interval: IntProperty(
name="Savestate Interval",
description="Number of frames between each savestate",
min=1,
default=50,
options={'HIDDEN'},
); exec(conv("savestate_interval"))
delete_outdated_savestates = BoolProperty(
)
delete_outdated_savestates: BoolProperty(
name="Delete Outdated Savestates on Resume",
description="When resuming a simulation from a previous frame, delete"
" all savestates that are ahead in the timeline",
default=True,
options = {'HIDDEN'},
); exec(conv("delete_outdated_savestates"))
delete_outdated_meshes = BoolProperty(
)
delete_outdated_meshes: BoolProperty(
name="Delete Outdated Meshes on Resume",
description="When resuming a simulation from a previous frame, delete"
" all simulation meshes that are ahead in the timeline",
default=True,
options = {'HIDDEN'},
); exec(conv("delete_outdated_meshes"))
selected_savestate = EnumProperty(
)
selected_savestate: EnumProperty(
name="Selected Savestate",
description="Resume simulation from this savestate frame",
update=lambda self, context: self._update_selected_savestate(context),
items=lambda self, context: self._get_savestate_enums(context),
); exec(conv("selected_savestate"))
selected_savestate_int = IntProperty(
)
selected_savestate_int: IntProperty(
name="Selected Savestate",
description="Resume simulation from this savestate frame",
update=lambda self, context: self._update_selected_savestate_int(context),
options={'HIDDEN'},
); exec(conv("selected_savestate_int"))
resolution = IntProperty(
)
resolution: IntProperty(
name="Resolution",
description="Domain grid resolution. This value specifies the number of"
" grid voxels on the longest side of the domain. See the tooltips in"
@@ -123,8 +122,8 @@ class DomainSimulationProperties(bpy.types.PropertyGroup):
default=65,
update=lambda self, context: self._update_resolution(context),
options={'HIDDEN'},
); exec(conv("resolution"))
preview_resolution = IntProperty(
)
preview_resolution: IntProperty(
name="Preview Resolution",
description="The resolution to use for generating lower quality meshes for"
" the preview fluid surface. Increasing this value will take no extra time"
@@ -133,16 +132,16 @@ class DomainSimulationProperties(bpy.types.PropertyGroup):
default=45,
update=lambda self, context: self._update_preview_resolution(context),
options={'HIDDEN'},
); exec(conv("preview_resolution"))
auto_preview_resolution = BoolProperty(
)
auto_preview_resolution: BoolProperty(
name="Recommended",
description="Set recommended preview resolution based on domain resolution and"
" mesh generation settings",
default=True,
update=lambda self, context: self._update_auto_preview_resolution(context),
options={'HIDDEN'},
); exec(conv("auto_preview_resolution"))
lock_cell_size = BoolProperty(
)
lock_cell_size: BoolProperty(
name="Lock Voxel Size",
description="Lock the current voxel size and update the grid"
" resolution as the domain dimensions are changed. Enable this"
@@ -151,16 +150,16 @@ class DomainSimulationProperties(bpy.types.PropertyGroup):
default=False,
update=lambda self, context: self._update_lock_cell_size(context),
options = {'HIDDEN'},
); exec(conv("lock_cell_size"))
fluid_boundary_collisions = BoolVectorProperty(
)
fluid_boundary_collisions: BoolVectorProperty(
name="",
description="Enable collisions on the corresponding side of the domain."
" If disabled, this side of the boundary will be open and will act"
" as an outflow",
default=(True, True, True, True, True, True),
size=6,
); exec(conv("fluid_boundary_collisions"))
fluid_open_boundary_width = IntProperty(
)
fluid_open_boundary_width: IntProperty(
name="Open Boundary Width",
description="The distance (in number of voxels) from the domain boundary that fluid will be"
" removed for open boundary sides. Note: This setting is for testing purposes and may"
@@ -168,22 +167,22 @@ class DomainSimulationProperties(bpy.types.PropertyGroup):
soft_min=2, min=1,
soft_max=10,
default=4,
); exec(conv("fluid_open_boundary_width"))
frame_rate_mode = EnumProperty(
)
frame_rate_mode: EnumProperty(
name="Frame Rate Mode",
description="Select the frame rate for the simulation animation",
items=types.frame_rate_modes,
default='FRAME_RATE_MODE_SCENE',
options={'HIDDEN'},
); exec(conv("frame_rate_mode"))
frame_rate_custom = FloatProperty(
)
frame_rate_custom: FloatProperty(
name="Frame Rate",
description="Frame rate in frames per second",
min=0.001,
default=60.0,
precision=2,
); exec(conv("frame_rate_custom"))
time_scale_mode = EnumProperty(
)
time_scale_mode: EnumProperty(
name="Time Scale Mode",
description="Select the time scale mode for the simulation. Use either a custom"
" value or match the value of another simulation. The simulation speed will be"
@@ -191,13 +190,16 @@ class DomainSimulationProperties(bpy.types.PropertyGroup):
items=types.time_scale_modes,
default='TIME_SCALE_MODE_CUSTOM',
options={'HIDDEN'},
); exec(conv("time_scale_mode"))
)
def time_scale_object_soft_body_poll(self, bl_object):
for mod in bl_object.modifiers:
if mod.type == 'SOFT_BODY':
return True
return False
def get_selected_time_scale_object_soft_body_modifier(self):
if self.time_scale_object_soft_body is None:
return None
@@ -205,18 +207,23 @@ class DomainSimulationProperties(bpy.types.PropertyGroup):
if mod.type == 'SOFT_BODY':
return mod
return None
time_scale_object_soft_body = PointerProperty(
time_scale_object_soft_body: PointerProperty(
name="Soft Body Object",
type=bpy.types.Object,
poll=time_scale_object_soft_body_poll,
options={'HIDDEN'},
); exec(conv("time_scale_object_soft_body"))
)
def time_scale_object_cloth_poll(self, bl_object):
for mod in bl_object.modifiers:
if mod.type == 'CLOTH':
return True
return False
def get_selected_time_scale_object_cloth_modifier(self):
if self.time_scale_object_cloth is None:
return None
@@ -224,37 +231,40 @@ class DomainSimulationProperties(bpy.types.PropertyGroup):
if mod.type == 'CLOTH':
return mod
return None
time_scale_object_cloth = PointerProperty(
time_scale_object_cloth: PointerProperty(
name="Cloth Object",
type=bpy.types.Object,
poll=time_scale_object_cloth_poll,
options={'HIDDEN'},
); exec(conv("time_scale_object_cloth"))
)
def time_scale_object_fluid_poll(self, bl_object):
if not vcu.is_blender_282():
return False
for mod in bl_object.modifiers:
if mod.type == 'FLUID' and mod.fluid_type == 'DOMAIN':
return True
return False
def get_selected_time_scale_object_fluid_modifier(self):
if not vcu.is_blender_282():
return False
if self.time_scale_object_fluid is None:
return None
for mod in self.time_scale_object_fluid.modifiers:
if mod.type == 'FLUID' and mod.fluid_type == 'DOMAIN':
return mod
return None
time_scale_object_fluid = PointerProperty(
time_scale_object_fluid: PointerProperty(
name="Fluid Domain Object",
type=bpy.types.Object,
poll=time_scale_object_fluid_poll,
options={'HIDDEN'},
); exec(conv("time_scale_object_fluid"))
)
time_scale = FloatProperty(
time_scale: FloatProperty(
name="Custom Time Scale",
description="Scale the simulation speed by this value. If set to less than"
" 1.0, the simulation will appear in slow motion. If set to greater than"
@@ -262,60 +272,52 @@ class DomainSimulationProperties(bpy.types.PropertyGroup):
min=0.0,
default=1.0,
precision=3,
); exec(conv("time_scale"))
)
locked_cell_size = FloatProperty(default=-1.0); exec(conv("locked_cell_size"))
frame_start = IntProperty(default=-1); exec(conv("frame_start"))
frame_end = IntProperty(default=-1); exec(conv("frame_end"))
locked_cell_size: FloatProperty(default=-1.0)
frame_start: IntProperty(default=-1)
frame_end: IntProperty(default=-1)
last_selected_savestate_int: IntProperty(default=-1)
selected_savestate_int_label: StringProperty(default="")
more_bake_settings_expanded = BoolProperty(default=False); exec(conv("more_bake_settings_expanded"))
skip_mesh_reexport_expanded = BoolProperty(default=False); exec(conv("skip_mesh_reexport_expanded"))
simulation_resolution_expanded = BoolProperty(default=False); exec(conv("simulation_resolution_expanded"))
grid_info_expanded = BoolProperty(default=False); exec(conv("grid_info_expanded"))
simulation_method_expanded = BoolProperty(default=False); exec(conv("simulation_method_expanded"))
world_scale_expanded = BoolProperty(default=False); exec(conv("world_scale_expanded"))
boundary_collisions_expanded = BoolProperty(default=False); exec(conv("boundary_collisions_expanded"))
frame_rate_and_time_scale_expanded = BoolProperty(default=False); exec(conv("frame_rate_and_time_scale_expanded"))
last_selected_savestate_int = IntProperty(default=-1); exec(conv("last_selected_savestate_int"))
selected_savestate_int_label = StringProperty(default=""); exec(conv("selected_savestate_int_label"))
current_isize: IntProperty(default=-1)
current_jsize: IntProperty(default=-1)
current_ksize: IntProperty(default=-1)
current_dx: FloatProperty(default=-1.0)
current_isize = IntProperty(default=-1); exec(conv("current_isize"))
current_jsize = IntProperty(default=-1); exec(conv("current_jsize"))
current_ksize = IntProperty(default=-1); exec(conv("current_ksize"))
current_dx = FloatProperty(default=-1.0); exec(conv("current_dx"))
savestate_isize: IntProperty(default=-1)
savestate_jsize: IntProperty(default=-1)
savestate_ksize: IntProperty(default=-1)
savestate_dx: FloatProperty(default=-1.0)
savestate_isize = IntProperty(default=-1); exec(conv("savestate_isize"))
savestate_jsize = IntProperty(default=-1); exec(conv("savestate_jsize"))
savestate_ksize = IntProperty(default=-1); exec(conv("savestate_ksize"))
savestate_dx = FloatProperty(default=-1.0); exec(conv("savestate_dx"))
upscale_trigger_factor: FloatProperty(default=0.05)
upscale_trigger_factor = FloatProperty(default=0.05); exec(conv("upscale_trigger_factor"))
upscale_resolution_tooltip = BoolProperty(
upscale_resolution_tooltip: BoolProperty(
name="Upscale Resolution Tooltip",
description="Upscaling converts a lower resolution savestate to a higher resolution savestate"
" so that the simulation can resume baking at the increased resolution",
default=True,
); exec(conv("upscale_resolution_tooltip"))
)
grid_voxels_tooltip = BoolProperty(
grid_voxels_tooltip: BoolProperty(
name="Grid Voxels Tooltip",
description="The domain is a 3D grid of cubes called voxels, or cells. This info shows the"
" number of voxels on each of the X/Y/Z axis of the domain. The voxels in the 3D grid are"
" similar to the 2D pixels in a 2D image, except instead of storing color data, the voxels store"
" physics data",
default=True,
); exec(conv("grid_voxels_tooltip"))
)
grid_dimensions_tooltip = BoolProperty(
grid_dimensions_tooltip: BoolProperty(
name="Grid Dimensions Tooltip",
description="Displays the physical scale of the domain on the X/Y/Z axis in meters."
" Setting an appropriate scale can be an important factor for realistic motion and speed"
" of your simulated fluid",
default=True,
); exec(conv("grid_dimensions_tooltip"))
)
grid_voxel_size_tooltip = BoolProperty(
grid_voxel_size_tooltip: BoolProperty(
name="Voxel Size Tooltip",
description="Displays the physical size of a single voxel. You can think of a voxel as"
" the 3D version of a 2D image pixel. In an image, the pixel size is the minimum"
@@ -323,16 +325,16 @@ class DomainSimulationProperties(bpy.types.PropertyGroup):
" the minimum amount of physics detail that can be resolved in the simulation such as the"
" smallest droplets and ripples or the thinnest splashes",
default=True,
); exec(conv("grid_voxel_size_tooltip"))
)
grid_voxel_count_tooltip = BoolProperty(
grid_voxel_count_tooltip: BoolProperty(
name="Voxel Count Tooltip",
description="Displays the total number of voxels in the domain. Physics are computed for each"
" voxel and the total count can be a measure for how much work your system will be doing."
" Small simulation = around 2 Million. Medium = around 10M. Large = around 40M."
" Very Large = over 80M",
default=True,
); exec(conv("grid_voxel_count_tooltip"))
)
def register_preset_properties(self, registry, path):
@@ -34,12 +34,11 @@ from ..operators import bake_operators
# ##############################################################################
class ByteProperty(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
bytes = FloatProperty(
bytes: FloatProperty(
default=-1.0,
get=lambda self: self._get_bytes(),
set=lambda self, value: self._set_bytes(value),
); exec(conv("bytes"))
)
def get(self):
@@ -62,27 +61,25 @@ class ByteProperty(bpy.types.PropertyGroup):
class MeshStatsProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
enabled = bpy.props.BoolProperty(default=False); exec(conv("enabled"))
verts = bpy.props.IntProperty(default=-1); exec(conv("verts"))
faces = bpy.props.IntProperty(default=-1); exec(conv("faces"))
bytes = PointerProperty(type=ByteProperty); exec(conv("bytes"))
enabled: bpy.props.BoolProperty(default=False)
verts: bpy.props.IntProperty(default=-1)
faces: bpy.props.IntProperty(default=-1)
bytes: PointerProperty(type=ByteProperty)
class TimeStatsProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
time = FloatProperty(
time: FloatProperty(
default=-1.0,
precision = 1
); exec(conv("time"))
pct = FloatProperty(
)
pct: FloatProperty(
min=0, max=100,
default=0.0,
precision = 1,
subtype='PERCENTAGE',
get=lambda self: self._get_time_pct(),
set=lambda self, value: None,
); exec(conv("pct"))
)
def set_time_pct(self, value):
@@ -97,8 +94,7 @@ class TimeStatsProperties(bpy.types.PropertyGroup):
class SolverStressProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
stress_level = FloatProperty(
stress_level: FloatProperty(
name="Stress Level",
description="Amount of stress experienced by the solver. If the stress level exceeds"
" 80% for multiple consecutive frames, this may indicate that the simulator requires"
@@ -112,7 +108,7 @@ class SolverStressProperties(bpy.types.PropertyGroup):
subtype='PERCENTAGE',
get=lambda self: self._get_stress_level_pct(),
set=lambda self, value: None,
); exec(conv("stress_level"))
)
def set_stress_level_pct(self, value):
@@ -127,178 +123,172 @@ class SolverStressProperties(bpy.types.PropertyGroup):
class DomainStatsProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
option_path_supports_blend_relative = set()
if vcu.is_blender_45():
# required for relative path support in Blender 4.5+
# https://docs.blender.org/api/4.5/bpy_types_enum_items/property_flag_items.html#rna-enum-property-flag-items
option_path_supports_blend_relative = {'PATH_SUPPORTS_BLEND_RELATIVE'}
# required for relative path support in Blender 4.5+
# https://docs.blender.org/api/4.5/bpy_types_enum_items/property_flag_items.html#rna-enum-property-flag-items
option_path_supports_blend_relative = {'PATH_SUPPORTS_BLEND_RELATIVE'}
cache_info_type = EnumProperty(
cache_info_type: EnumProperty(
name="Cache Info Display Mode",
description="Type of cache info to display",
items=types.cache_info_modes,
default='CACHE_INFO',
update=lambda self, context: self._update_cache_info_type(context),
); exec(conv("cache_info_type"))
current_info_frame = IntProperty(
)
current_info_frame: IntProperty(
name="Frame",
description="Select frame number",
min=0,
default=0,
update=lambda self, context: self._update_current_info_frame(context),
); exec(conv("current_info_frame"))
lock_info_frame_to_timeline = BoolProperty(
)
lock_info_frame_to_timeline: BoolProperty(
name="Lock To Timeline",
description="Set frame number to current frame in timeline",
default=True,
update=lambda self, context: self._update_lock_info_frame_to_timeline(context),
); exec(conv("lock_info_frame_to_timeline"))
)
temp_directory = vcu.get_blender_preferences_temporary_directory()
csv_save_filepath = StringProperty(
csv_save_filepath: StringProperty(
name="",
default=os.path.join(temp_directory, "flip_fluid_stats.csv"),
subtype='FILE_PATH',
options=option_path_supports_blend_relative,
); exec(conv("csv_save_filepath"))
csv_region_format = EnumProperty(
)
csv_region_format: EnumProperty(
name="Region Format",
description="CSV region formatting",
items=types.csv_regions,
default='CSV_REGION_US',
); exec(conv("csv_region_format"))
)
stats_filename = bpy.props.StringProperty(default='flipstats.data'); exec(conv("stats_filename"))
is_stats_current = bpy.props.BoolProperty(default=False); exec(conv("is_stats_current"))
stats_filename: bpy.props.StringProperty(default='flipstats.data')
is_stats_current: bpy.props.BoolProperty(default=False)
# Cache Info
cache_info_simulation_stats_expanded = BoolProperty(default=True); exec(conv("cache_info_simulation_stats_expanded"))
cache_info_timing_stats_expanded = BoolProperty(default=True); exec(conv("cache_info_timing_stats_expanded"))
cache_info_mesh_stats_expanded = BoolProperty(default=True); exec(conv("cache_info_mesh_stats_expanded"))
cache_info_solver_stats_expanded = BoolProperty(default=True); exec(conv("cache_info_solver_stats_expanded"))
cache_info_pressure_solver_stats_expanded = BoolProperty(default=True); exec(conv("cache_info_pressure_solver_stats_expanded"))
cache_info_viscosity_solver_stats_expanded = BoolProperty(default=True); exec(conv("cache_info_viscosity_solver_stats_expanded"))
is_cache_info_available = BoolProperty(default=False); exec(conv("is_cache_info_available"))
frame_start = IntProperty(default=-1); exec(conv("frame_start"))
num_cache_frames = IntProperty(default=-1); exec(conv("num_cache_frames"))
is_average_performance_score_enabled = BoolProperty(default=False); exec(conv("is_average_performance_score_enabled"))
average_performance_score = IntProperty(default=-1); exec(conv("average_performance_score"))
estimated_frame_speed = FloatProperty(default=-1); exec(conv("estimated_frame_speed"))
estimated_time_remaining = IntProperty(default=-1); exec(conv("estimated_time_remaining"))
estimated_time_remaining_timestamp = IntProperty(default=-1); exec(conv("estimated_time_remaining_timestamp"))
is_estimated_time_remaining_available = BoolProperty(default=False); exec(conv("is_estimated_time_remaining_available"))
cache_bytes = PointerProperty(type=ByteProperty); exec(conv("cache_bytes"))
is_cache_info_available: BoolProperty(default=False)
frame_start: IntProperty(default=-1)
num_cache_frames: IntProperty(default=-1)
is_average_performance_score_enabled: BoolProperty(default=False)
average_performance_score: IntProperty(default=-1)
estimated_frame_speed: FloatProperty(default=-1)
estimated_time_remaining: IntProperty(default=-1)
estimated_time_remaining_timestamp: IntProperty(default=-1)
is_estimated_time_remaining_available: BoolProperty(default=False)
cache_bytes: PointerProperty(type=ByteProperty)
pressure_solver_enabled = BoolProperty(default=False); exec(conv("pressure_solver_enabled"))
pressure_solver_failures = IntProperty(default=-1); exec(conv("pressure_solver_failures"))
pressure_solver_steps = IntProperty(default=-1); exec(conv("pressure_solver_steps"))
pressure_solver_max_iterations = IntProperty(default=-1); exec(conv("pressure_solver_max_iterations"))
pressure_solver_max_iterations_frame = IntProperty(default=-1); exec(conv("pressure_solver_max_iterations_frame"))
pressure_solver_max_error = FloatProperty(default=-1); exec(conv("pressure_solver_max_error"))
pressure_solver_max_error_frame = IntProperty(default=-1); exec(conv("pressure_solver_max_error_frame"))
pressure_solver_max_stress = FloatProperty(default=-1); exec(conv("pressure_solver_max_stress"))
pressure_solver_max_stress_frame = IntProperty(default=-1); exec(conv("pressure_solver_max_stress_frame"))
pressure_solver_enabled: BoolProperty(default=False)
pressure_solver_failures: IntProperty(default=-1)
pressure_solver_steps: IntProperty(default=-1)
pressure_solver_max_iterations: IntProperty(default=-1)
pressure_solver_max_iterations_frame: IntProperty(default=-1)
pressure_solver_max_error: FloatProperty(default=-1)
pressure_solver_max_error_frame: IntProperty(default=-1)
pressure_solver_max_stress: FloatProperty(default=-1)
pressure_solver_max_stress_frame: IntProperty(default=-1)
viscosity_solver_enabled = BoolProperty(default=False); exec(conv("viscosity_solver_enabled"))
viscosity_solver_failures = IntProperty(default=-1); exec(conv("viscosity_solver_failures"))
viscosity_solver_steps = IntProperty(default=-1); exec(conv("viscosity_solver_steps"))
viscosity_solver_max_iterations = IntProperty(default=-1); exec(conv("viscosity_solver_max_iterations"))
viscosity_solver_max_iterations_frame = IntProperty(default=-1); exec(conv("viscosity_solver_max_iterations_frame"))
viscosity_solver_max_error = FloatProperty(default=-1); exec(conv("viscosity_solver_max_error"))
viscosity_solver_max_error_frame = IntProperty(default=-1); exec(conv("viscosity_solver_max_error_frame"))
viscosity_solver_max_stress = FloatProperty(default=-1); exec(conv("viscosity_solver_max_stress"))
viscosity_solver_max_stress_frame = IntProperty(default=-1); exec(conv("viscosity_solver_max_stress_frame"))
viscosity_solver_enabled: BoolProperty(default=False)
viscosity_solver_failures: IntProperty(default=-1)
viscosity_solver_steps: IntProperty(default=-1)
viscosity_solver_max_iterations: IntProperty(default=-1)
viscosity_solver_max_iterations_frame: IntProperty(default=-1)
viscosity_solver_max_error: FloatProperty(default=-1)
viscosity_solver_max_error_frame: IntProperty(default=-1)
viscosity_solver_max_stress: FloatProperty(default=-1)
viscosity_solver_max_stress_frame: IntProperty(default=-1)
# Frame Info
frame_info_simulation_stats_expanded = BoolProperty(default=True); exec(conv("frame_info_simulation_stats_expanded"))
frame_info_solver_stats_expanded = BoolProperty(default=True); exec(conv("frame_info_solver_stats_expanded"))
frame_info_pressure_solver_stats_expanded = BoolProperty(default=True); exec(conv("frame_info_pressure_solver_stats_expanded"))
frame_info_viscosity_solver_stats_expanded = BoolProperty(default=True); exec(conv("frame_info_viscosity_solver_stats_expanded"))
frame_info_timing_stats_expanded = BoolProperty(default=True); exec(conv("frame_info_timing_stats_expanded"))
frame_info_mesh_stats_expanded = BoolProperty(default=True); exec(conv("frame_info_mesh_stats_expanded"))
display_frame_viscosity_timing_stats = BoolProperty(default=False); exec(conv("display_frame_viscosity_timing_stats"))
display_frame_diffuse_timing_stats = BoolProperty(default=False); exec(conv("display_frame_diffuse_timing_stats"))
display_frame_diffuse_particle_stats = BoolProperty(default=False); exec(conv("display_frame_diffuse_particle_stats"))
is_frame_info_available = bpy.props.BoolProperty(default=False); exec(conv("is_frame_info_available"))
frame_info_id = IntProperty(default=-1); exec(conv("frame_info_id"))
frame_substeps = IntProperty(default=-1); exec(conv("frame_substeps"))
frame_delta_time = FloatProperty(default=0.0); exec(conv("frame_delta_time"))
frame_fluid_particles = IntProperty(default=-1); exec(conv("frame_fluid_particles"))
frame_diffuse_particles = IntProperty(default=-1); exec(conv("frame_diffuse_particles"))
frame_performance_score = IntProperty(default=-1); exec(conv("frame_performance_score"))
frame_info_simulation_stats_expanded: BoolProperty(default=True)
frame_info_solver_stats_expanded: BoolProperty(default=True)
frame_info_pressure_solver_stats_expanded: BoolProperty(default=True)
frame_info_viscosity_solver_stats_expanded: BoolProperty(default=True)
frame_info_timing_stats_expanded: BoolProperty(default=True)
frame_info_mesh_stats_expanded: BoolProperty(default=True)
display_frame_viscosity_timing_stats: BoolProperty(default=False)
display_frame_diffuse_timing_stats: BoolProperty(default=False)
display_frame_diffuse_particle_stats: BoolProperty(default=False)
is_frame_info_available: bpy.props.BoolProperty(default=False)
frame_info_id: IntProperty(default=-1)
frame_substeps: IntProperty(default=-1)
frame_delta_time: FloatProperty(default=0.0)
frame_fluid_particles: IntProperty(default=-1)
frame_diffuse_particles: IntProperty(default=-1)
frame_performance_score: IntProperty(default=-1)
frame_pressure_solver_enabled = BoolProperty(default=False); exec(conv("frame_pressure_solver_enabled"))
frame_pressure_solver_success = BoolProperty(default=True); exec(conv("frame_pressure_solver_success"))
frame_pressure_solver_error = FloatProperty(default=0.0); exec(conv("frame_pressure_solver_error"))
frame_pressure_solver_iterations = IntProperty(default=-1); exec(conv("frame_pressure_solver_iterations"))
frame_pressure_solver_max_iterations = IntProperty(default=-1); exec(conv("frame_pressure_solver_max_iterations"))
frame_pressure_solver_stress = PointerProperty(type=SolverStressProperties); exec(conv("frame_pressure_solver_stress"))
frame_pressure_solver_enabled: BoolProperty(default=False)
frame_pressure_solver_success: BoolProperty(default=True)
frame_pressure_solver_error: FloatProperty(default=0.0)
frame_pressure_solver_iterations: IntProperty(default=-1)
frame_pressure_solver_max_iterations: IntProperty(default=-1)
frame_pressure_solver_stress: PointerProperty(type=SolverStressProperties)
frame_viscosity_solver_enabled = BoolProperty(default=False); exec(conv("frame_viscosity_solver_enabled"))
frame_viscosity_solver_success = BoolProperty(default=True); exec(conv("frame_viscosity_solver_success"))
frame_viscosity_solver_error = FloatProperty(default=0.0); exec(conv("frame_viscosity_solver_error"))
frame_viscosity_solver_iterations = IntProperty(default=-1); exec(conv("frame_viscosity_solver_iterations"))
frame_viscosity_solver_max_iterations = IntProperty(default=-1); exec(conv("frame_viscosity_solver_max_iterations"))
frame_viscosity_solver_stress = PointerProperty(type=SolverStressProperties); exec(conv("frame_viscosity_solver_stress"))
frame_viscosity_solver_enabled: BoolProperty(default=False)
frame_viscosity_solver_success: BoolProperty(default=True)
frame_viscosity_solver_error: FloatProperty(default=0.0)
frame_viscosity_solver_iterations: IntProperty(default=-1)
frame_viscosity_solver_max_iterations: IntProperty(default=-1)
frame_viscosity_solver_stress: PointerProperty(type=SolverStressProperties)
# Mesh Info
surface_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("surface_mesh"))
preview_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("preview_mesh"))
surfaceblur_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("surfaceblur_mesh"))
surfacevelocity_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("surfacevelocity_mesh"))
surfacespeed_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("surfacespeed_mesh"))
surfacevorticity_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("surfacevorticity_mesh"))
surfaceage_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("surfaceage_mesh"))
surfacelifetime_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("surfacelifetime_mesh"))
surfacewhitewaterproximity_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("surfacewhitewaterproximity_mesh"))
surfacecolor_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("surfacecolor_mesh"))
surfacesourceid_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("surfacesourceid_mesh"))
surfaceviscosity_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("surfaceviscosity_mesh"))
foam_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("foam_mesh"))
bubble_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("bubble_mesh"))
spray_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("spray_mesh"))
dust_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("dust_mesh"))
foamblur_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("foamblur_mesh"))
bubbleblur_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("bubbleblur_mesh"))
sprayblur_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("sprayblur_mesh"))
dustblur_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("dustblur_mesh"))
foamvelocity_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("foamvelocity_mesh"))
bubblevelocity_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("bubblevelocity_mesh"))
sprayvelocity_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("sprayvelocity_mesh"))
dustvelocity_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("dustvelocity_mesh"))
foamid_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("foamid_mesh"))
bubbleid_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("bubbleid_mesh"))
sprayid_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("sprayid_mesh"))
dustid_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("dustid_mesh"))
foamlifetime_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("foamlifetime_mesh"))
bubblelifetime_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("bubblelifetime_mesh"))
spraylifetime_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("spraylifetime_mesh"))
dustlifetime_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("dustlifetime_mesh"))
fluid_particle_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("fluid_particle_mesh"))
fluid_particle_id_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("fluid_particle_id_mesh"))
fluid_particle_velocity_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("fluid_particle_velocity_mesh"))
fluid_particle_speed_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("fluid_particle_speed_mesh"))
fluid_particle_vorticity_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("fluid_particle_vorticity_mesh"))
fluid_particle_color_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("fluid_particle_color_mesh"))
fluid_particle_age_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("fluid_particle_age_mesh"))
fluid_particle_lifetime_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("fluid_particle_lifetime_mesh"))
fluid_particle_viscosity_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("fluid_particle_viscosity_mesh"))
fluid_particle_whitewater_proximity_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("fluid_particle_whitewater_proximity_mesh"))
fluid_particle_source_id_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("fluid_particle_source_id_mesh"))
fluid_particle_uid_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("fluid_particle_uid_mesh"))
debug_particle_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("debug_particle_mesh"))
obstacle_mesh = PointerProperty(type=MeshStatsProperties); exec(conv("obstacle_mesh"))
surface_mesh: PointerProperty(type=MeshStatsProperties)
preview_mesh: PointerProperty(type=MeshStatsProperties)
surfaceblur_mesh: PointerProperty(type=MeshStatsProperties)
surfacevelocity_mesh: PointerProperty(type=MeshStatsProperties)
surfacespeed_mesh: PointerProperty(type=MeshStatsProperties)
surfacevorticity_mesh: PointerProperty(type=MeshStatsProperties)
surfaceage_mesh: PointerProperty(type=MeshStatsProperties)
surfacelifetime_mesh: PointerProperty(type=MeshStatsProperties)
surfacewhitewaterproximity_mesh: PointerProperty(type=MeshStatsProperties)
surfacecolor_mesh: PointerProperty(type=MeshStatsProperties)
surfacesourceid_mesh: PointerProperty(type=MeshStatsProperties)
surfaceviscosity_mesh: PointerProperty(type=MeshStatsProperties)
surfacedensity_mesh: PointerProperty(type=MeshStatsProperties)
foam_mesh: PointerProperty(type=MeshStatsProperties)
bubble_mesh: PointerProperty(type=MeshStatsProperties)
spray_mesh: PointerProperty(type=MeshStatsProperties)
dust_mesh: PointerProperty(type=MeshStatsProperties)
foamblur_mesh: PointerProperty(type=MeshStatsProperties)
bubbleblur_mesh: PointerProperty(type=MeshStatsProperties)
sprayblur_mesh: PointerProperty(type=MeshStatsProperties)
dustblur_mesh: PointerProperty(type=MeshStatsProperties)
foamvelocity_mesh: PointerProperty(type=MeshStatsProperties)
bubblevelocity_mesh: PointerProperty(type=MeshStatsProperties)
sprayvelocity_mesh: PointerProperty(type=MeshStatsProperties)
dustvelocity_mesh: PointerProperty(type=MeshStatsProperties)
foamid_mesh: PointerProperty(type=MeshStatsProperties)
bubbleid_mesh: PointerProperty(type=MeshStatsProperties)
sprayid_mesh: PointerProperty(type=MeshStatsProperties)
dustid_mesh: PointerProperty(type=MeshStatsProperties)
foamlifetime_mesh: PointerProperty(type=MeshStatsProperties)
bubblelifetime_mesh: PointerProperty(type=MeshStatsProperties)
spraylifetime_mesh: PointerProperty(type=MeshStatsProperties)
dustlifetime_mesh: PointerProperty(type=MeshStatsProperties)
fluid_particle_mesh: PointerProperty(type=MeshStatsProperties)
fluid_particle_id_mesh: PointerProperty(type=MeshStatsProperties)
fluid_particle_velocity_mesh: PointerProperty(type=MeshStatsProperties)
fluid_particle_speed_mesh: PointerProperty(type=MeshStatsProperties)
fluid_particle_vorticity_mesh: PointerProperty(type=MeshStatsProperties)
fluid_particle_color_mesh: PointerProperty(type=MeshStatsProperties)
fluid_particle_age_mesh: PointerProperty(type=MeshStatsProperties)
fluid_particle_lifetime_mesh: PointerProperty(type=MeshStatsProperties)
fluid_particle_viscosity_mesh: PointerProperty(type=MeshStatsProperties)
fluid_particle_density_mesh: PointerProperty(type=MeshStatsProperties)
fluid_particle_density_average_mesh: PointerProperty(type=MeshStatsProperties)
fluid_particle_whitewater_proximity_mesh: PointerProperty(type=MeshStatsProperties)
fluid_particle_source_id_mesh: PointerProperty(type=MeshStatsProperties)
fluid_particle_uid_mesh: PointerProperty(type=MeshStatsProperties)
debug_particle_mesh: PointerProperty(type=MeshStatsProperties)
obstacle_mesh: PointerProperty(type=MeshStatsProperties)
# Time Info
time_mesh = PointerProperty(type=TimeStatsProperties); exec(conv("time_mesh"))
time_advection = PointerProperty(type=TimeStatsProperties); exec(conv("time_advection"))
time_particles = PointerProperty(type=TimeStatsProperties); exec(conv("time_particles"))
time_pressure = PointerProperty(type=TimeStatsProperties); exec(conv("time_pressure"))
time_diffuse = PointerProperty(type=TimeStatsProperties); exec(conv("time_diffuse"))
time_viscosity = PointerProperty(type=TimeStatsProperties); exec(conv("time_viscosity"))
time_objects = PointerProperty(type=TimeStatsProperties); exec(conv("time_objects"))
time_other = PointerProperty(type=TimeStatsProperties); exec(conv("time_other"))
time_mesh: PointerProperty(type=TimeStatsProperties)
time_advection: PointerProperty(type=TimeStatsProperties)
time_particles: PointerProperty(type=TimeStatsProperties)
time_pressure: PointerProperty(type=TimeStatsProperties)
time_diffuse: PointerProperty(type=TimeStatsProperties)
time_viscosity: PointerProperty(type=TimeStatsProperties)
time_objects: PointerProperty(type=TimeStatsProperties)
time_other: PointerProperty(type=TimeStatsProperties)
def register_preset_properties(self, registry, path):
@@ -366,6 +356,7 @@ class DomainStatsProperties(bpy.types.PropertyGroup):
"surfacecolor_mesh",
"surfacesourceid_mesh",
"surfaceviscosity_mesh",
"surfacedensity_mesh",
"foam_mesh",
"bubble_mesh",
"spray_mesh",
@@ -395,6 +386,8 @@ class DomainStatsProperties(bpy.types.PropertyGroup):
"fluid_particle_age_mesh",
"fluid_particle_lifetime_mesh",
"fluid_particle_viscosity_mesh",
"fluid_particle_density_mesh",
"fluid_particle_density_average_mesh",
"fluid_particle_whitewater_proximity_mesh",
"fluid_particle_source_id_mesh",
"fluid_particle_uid_mesh",
@@ -582,6 +575,10 @@ class DomainStatsProperties(bpy.types.PropertyGroup):
# If statement to support older caches that do not have a surfaceviscosity entry
self._set_mesh_stats_data(self.surfaceviscosity_mesh, data['surfaceviscosity'])
if 'surfacedensity' in data:
# If statement to support older caches that do not have a surfacedensity entry
self._set_mesh_stats_data(self.surfacedensity_mesh, data['surfacedensity'])
self._set_mesh_stats_data(self.foam_mesh, data['foam'])
self._set_mesh_stats_data(self.bubble_mesh, data['bubble'])
self._set_mesh_stats_data(self.spray_mesh, data['spray'])
@@ -661,6 +658,14 @@ class DomainStatsProperties(bpy.types.PropertyGroup):
# If statement to support older caches that do not have a fluidparticlesviscosity entry
self._set_mesh_stats_data(self.fluid_particle_viscosity_mesh, data['fluidparticlesviscosity'])
if 'fluidparticlesdensity' in data:
# If statement to support older caches that do not have a fluidparticlesdensity entry
self._set_mesh_stats_data(self.fluid_particle_density_mesh, data['fluidparticlesdensity'])
if 'fluidparticlesdensityaverage' in data:
# If statement to support older caches that do not have a fluidparticlesdensityaverage entry
self._set_mesh_stats_data(self.fluid_particle_density_average_mesh, data['fluidparticlesdensityaverage'])
if 'fluidparticleswhitewaterproximity' in data:
# If statement to support older caches that do not have a fluidparticleswhitewaterproximity entry
self._set_mesh_stats_data(self.fluid_particle_whitewater_proximity_mesh, data['fluidparticleswhitewaterproximity'])
@@ -765,6 +770,8 @@ class DomainStatsProperties(bpy.types.PropertyGroup):
cache_size += fdata['surfacesourceid']['bytes']
if 'surfaceviscosity' in fdata and fdata['surfaceviscosity']['enabled']: # If statement to support caches without a surfaceviscosity entry
cache_size += fdata['surfaceviscosity']['bytes']
if 'surfacedensity' in fdata and fdata['surfacedensity']['enabled']: # If statement to support caches without a surfacedensity entry
cache_size += fdata['surfacedensity']['bytes']
if fdata['foam']['enabled']:
cache_size += fdata['foam']['bytes']
if fdata['bubble']['enabled']:
@@ -823,6 +830,10 @@ class DomainStatsProperties(bpy.types.PropertyGroup):
cache_size += fdata['fluidparticleslifetime']['bytes']
if 'fluidparticlesviscosity' in fdata and fdata['fluidparticlesviscosity']['enabled']:
cache_size += fdata['fluidparticlesviscosity']['bytes']
if 'fluidparticlesdensity' in fdata and fdata['fluidparticlesdensity']['enabled']:
cache_size += fdata['fluidparticlesdensity']['bytes']
if 'fluidparticlesdensityaverage' in fdata and fdata['fluidparticlesdensityaverage']['enabled']:
cache_size += fdata['fluidparticlesdensityaverage']['bytes']
if 'fluidparticleswhitewaterproximity' in fdata and fdata['fluidparticleswhitewaterproximity']['enabled']:
cache_size += fdata['fluidparticleswhitewaterproximity']['bytes']
if 'fluidparticlessourceid' in fdata and fdata['fluidparticlessourceid']['enabled']:
@@ -870,6 +881,7 @@ class DomainStatsProperties(bpy.types.PropertyGroup):
is_surfacecolor_enabled = False
is_surfacesourceid_enabled = False
is_surfaceviscosity_enabled = False
is_surfacedensity_enabled = False
is_foam_enabled = False
is_bubble_enabled = False
is_spray_enabled = False
@@ -899,6 +911,8 @@ class DomainStatsProperties(bpy.types.PropertyGroup):
is_fluid_particles_age_enabled = False
is_fluid_particles_lifetime_enabled = False
is_fluid_particles_viscosity_enabled = False
is_fluid_particles_density_enabled = False
is_fluid_particles_density_average_enabled = False
is_fluid_particles_whitewater_proximity_enabled = False
is_fluid_particles_source_id_enabled = False
is_fluid_particles_uid_enabled = False
@@ -916,6 +930,7 @@ class DomainStatsProperties(bpy.types.PropertyGroup):
surfacecolor_bytes = 0
surfacesourceid_bytes = 0
surfaceviscosity_bytes = 0
surfacedensity_bytes = 0
foam_bytes = 0
bubble_bytes = 0
spray_bytes = 0
@@ -945,6 +960,8 @@ class DomainStatsProperties(bpy.types.PropertyGroup):
fluid_particles_age_bytes = 0
fluid_particles_lifetime_bytes = 0
fluid_particles_viscosity_bytes = 0
fluid_particles_density_bytes = 0
fluid_particles_density_average_bytes = 0
fluid_particles_whitewater_proximity_bytes = 0
fluid_particles_source_id_bytes = 0
fluid_particles_uid_bytes = 0
@@ -1015,6 +1032,9 @@ class DomainStatsProperties(bpy.types.PropertyGroup):
if 'surfaceviscosity' in fdata and fdata['surfaceviscosity']['enabled']: # If statement to support caches without a surfaceviscosity entry
is_surfaceviscosity_enabled = True
surfaceviscosity_bytes += fdata['surfaceviscosity']['bytes']
if 'surfacedensity' in fdata and fdata['surfacedensity']['enabled']: # If statement to support caches without a surfacedensity entry
is_surfacedensity_enabled = True
surfacedensity_bytes += fdata['surfacedensity']['bytes']
if fdata['foam']['enabled']:
is_foam_enabled = True
foam_bytes += fdata['foam']['bytes']
@@ -1102,6 +1122,12 @@ class DomainStatsProperties(bpy.types.PropertyGroup):
if 'fluidparticlesviscosity' in fdata and fdata['fluidparticlesviscosity']['enabled']:
is_fluid_particles_viscosity_enabled = True
fluid_particles_viscosity_bytes += fdata['fluidparticlesviscosity']['bytes']
if 'fluidparticlesdensity' in fdata and fdata['fluidparticlesdensity']['enabled']:
is_fluid_particles_density_enabled = True
fluid_particles_density_bytes += fdata['fluidparticlesdensity']['bytes']
if 'fluidparticlesdensityaverage' in fdata and fdata['fluidparticlesdensityaverage']['enabled']:
is_fluid_particles_density_average_enabled = True
fluid_particles_density_average_bytes += fdata['fluidparticlesdensityaverage']['bytes']
if 'fluidparticleswhitewaterproximity' in fdata and fdata['fluidparticleswhitewaterproximity']['enabled']:
is_fluid_particles_whitewater_proximity_enabled = True
fluid_particles_whitewater_proximity_bytes += fdata['fluidparticleswhitewaterproximity']['bytes']
@@ -1154,6 +1180,7 @@ class DomainStatsProperties(bpy.types.PropertyGroup):
self.surfacecolor_mesh.enabled = is_surfacecolor_enabled
self.surfacesourceid_mesh.enabled = is_surfacesourceid_enabled
self.surfaceviscosity_mesh.enabled = is_surfaceviscosity_enabled
self.surfacedensity_mesh.enabled = is_surfacedensity_enabled
self.foam_mesh.enabled = is_foam_enabled
self.bubble_mesh.enabled = is_bubble_enabled
self.spray_mesh.enabled = is_spray_enabled
@@ -1183,6 +1210,8 @@ class DomainStatsProperties(bpy.types.PropertyGroup):
self.fluid_particle_age_mesh.enabled = is_fluid_particles_age_enabled
self.fluid_particle_lifetime_mesh.enabled = is_fluid_particles_lifetime_enabled
self.fluid_particle_viscosity_mesh.enabled = is_fluid_particles_viscosity_enabled
self.fluid_particle_density_mesh.enabled = is_fluid_particles_density_enabled
self.fluid_particle_density_average_mesh.enabled = is_fluid_particles_density_average_enabled
self.fluid_particle_whitewater_proximity_mesh.enabled = is_fluid_particles_whitewater_proximity_enabled
self.fluid_particle_source_id_mesh.enabled = is_fluid_particles_source_id_enabled
self.fluid_particle_uid_mesh.enabled = is_fluid_particles_uid_enabled
@@ -1201,6 +1230,7 @@ class DomainStatsProperties(bpy.types.PropertyGroup):
self.surfacecolor_mesh.bytes.set(surfacecolor_bytes)
self.surfacesourceid_mesh.bytes.set(surfacesourceid_bytes)
self.surfaceviscosity_mesh.bytes.set(surfaceviscosity_bytes)
self.surfacedensity_mesh.bytes.set(surfacedensity_bytes)
self.foam_mesh.bytes.set(foam_bytes)
self.bubble_mesh.bytes.set(bubble_bytes)
self.spray_mesh.bytes.set(spray_bytes)
@@ -1230,6 +1260,8 @@ class DomainStatsProperties(bpy.types.PropertyGroup):
self.fluid_particle_age_mesh.bytes.set(fluid_particles_age_bytes)
self.fluid_particle_lifetime_mesh.bytes.set(fluid_particles_lifetime_bytes)
self.fluid_particle_viscosity_mesh.bytes.set(fluid_particles_viscosity_bytes)
self.fluid_particle_density_mesh.bytes.set(fluid_particles_density_bytes)
self.fluid_particle_density_average_mesh.bytes.set(fluid_particles_density_average_bytes)
self.fluid_particle_whitewater_proximity_mesh.bytes.set(fluid_particles_whitewater_proximity_bytes)
self.fluid_particle_source_id_mesh.bytes.set(fluid_particles_source_id_bytes)
self.fluid_particle_uid_mesh.bytes.set(fluid_particles_uid_bytes)
@@ -30,17 +30,16 @@ from ..objects import flip_fluid_cache
from ..utils import version_compatibility_utils as vcu
class DomainSurfaceProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
enable_surface_mesh_generation = BoolProperty(
enable_surface_mesh_generation: BoolProperty(
name="Enable Surface Mesh Generation",
description="Enable the generation of the liquid surface mesh. If disabled, "
"the surface mesh and any surface attributes will not be generated or exported"
" to the simulation cache",
default=True,
update=lambda self, context: self._update_enable_surface_mesh_generation(context),
); exec(conv("enable_surface_mesh_generation"))
subdivisions = IntProperty(
)
subdivisions: IntProperty(
name="Subdivisions",
description="The level of detail of the generated surface mesh."
" This value is the number of times that the simulation grid"
@@ -51,88 +50,88 @@ class DomainSurfaceProperties(bpy.types.PropertyGroup):
min=0,
soft_max=2,
default=1,
); exec(conv("subdivisions"))
compute_chunks_auto = IntProperty(
)
compute_chunks_auto: IntProperty(
name="Compute Chunks",
description="Number of chunks to break up mesh into during"
" computation. Increase to reduce memory usage",
min=1,
default=1,
); exec(conv("compute_chunks_auto"))
compute_chunks_fixed = IntProperty(
)
compute_chunks_fixed: IntProperty(
name="Compute Chunks",
description="Number of chunks to break up surface into during"
" mesh generation. Increase to reduce memory usage",
min=1,
default=1,
); exec(conv("compute_chunks_fixed"))
compute_chunk_mode = EnumProperty(
)
compute_chunk_mode: EnumProperty(
name="Threading Mode",
description="Determine the number of compute chunks to use when"
" generating the surface mesh",
items=types.surface_compute_chunk_modes,
default='COMPUTE_CHUNK_MODE_AUTO',
options={'HIDDEN'},
); exec(conv("compute_chunk_mode"))
meshing_volume_mode = EnumProperty(
)
meshing_volume_mode: EnumProperty(
name="Meshing Volume Mode",
description="Determing which parts of the fluid will be meshed",
items=types.meshing_volume_modes,
default='MESHING_VOLUME_MODE_DOMAIN',
options={'HIDDEN'},
); exec(conv("meshing_volume_mode"))
meshing_volume_object = PointerProperty(
)
meshing_volume_object: PointerProperty(
name="Meshing Object",
description="Only fluid that is inside of this object will be meshed",
type=bpy.types.Object,
update=lambda self, context: self._update_meshing_volume_object(context),
poll=lambda self, obj: self._poll_meshing_volume_object(obj),
); exec(conv("meshing_volume_object"))
export_animated_meshing_volume_object = BoolProperty(
)
export_animated_meshing_volume_object: BoolProperty(
name="Export Animated Mesh",
description="Export this mesh as an animated one (slower, only use"
" if really necessary [e.g. armatures or parented objects],"
" animated pos/rot/scale F-curves do not require it",
default=False,
options={'HIDDEN'},
); exec(conv("export_animated_meshing_volume_object"))
enable_meshing_offset = BoolProperty(
)
enable_meshing_offset: BoolProperty(
name="Enable",
description="Enable smooth meshing against obstacles. If disabled,"
" obstacles will not be considered during meshing and all fluid"
" particles will be converted to a mesh",
default=True,
); exec(conv("enable_meshing_offset"))
obstacle_meshing_mode = EnumProperty(
)
obstacle_meshing_mode: EnumProperty(
name="Obstacle Meshing Mode",
description="How the fluid surface will be meshed against obstacles",
items=types.obstacle_meshing_modes,
default='MESHING_MODE_INSIDE_SURFACE',
); exec(conv("obstacle_meshing_mode"))
remove_mesh_near_domain = BoolProperty(
)
remove_mesh_near_domain: BoolProperty(
name="Remove Mesh Near Boundary",
description="Remove parts of the surface mesh that are near the"
" domain boundary. If a meshing volume object is set, parts"
" of the mesh that are near the volume object boundary will"
" also be removed",
default=False,
); exec(conv("remove_mesh_near_domain"))
remove_mesh_near_domain_distance = IntProperty(
)
remove_mesh_near_domain_distance: IntProperty(
name="Distance",
description="Distance from domain boundary to remove mesh parts."
" This value is in number of voxels. If a meshing volume"
" object is set, this distance will be limited to 1 voxel",
min=1,
default=1,
); exec(conv("remove_mesh_near_domain_distance"))
remove_mesh_near_domain_sides = BoolVectorProperty(
)
remove_mesh_near_domain_sides: BoolVectorProperty(
name="",
description="Remove mesh on the corresponding side of the domain."
" If disabled, this side of the mesh will not be removed",
default=(True, True, True, True, True, True),
size=6,
); exec(conv("remove_mesh_near_domain_sides"))
smoothing_value = FloatProperty(
)
smoothing_value: FloatProperty(
name="Factor",
description="Amount of surface smoothing. Tip: use a smooth modifier"
" to increase amount of smoothing",
@@ -140,37 +139,37 @@ class DomainSurfaceProperties(bpy.types.PropertyGroup):
default=0.5,
precision=3,
subtype='FACTOR',
); exec(conv("smoothing_value"))
smoothing_iterations = IntProperty(
)
smoothing_iterations: IntProperty(
name="Repeat",
description="Number of smoothing iterations Tip: use a smooth modifier"
" to increase amount of iterations",
min=0, max=30,
default=2,
); exec(conv("smoothing_iterations"))
particle_scale = FloatProperty(
)
particle_scale: FloatProperty(
name="Particle Scale",
description = "Size of particles for mesh generation. A value less than 1.0"
" is not recommended and may result in an incomplete mesh",
soft_min=1.0, soft_max=3.0,
default=1.0,
precision=2,
); exec(conv("particle_scale"))
invert_contact_normals = BoolProperty(
)
invert_contact_normals: BoolProperty(
name="Invert Fluid-Obstacle Contact Normals",
description="Invert surface mesh normals that contact obstacle"
" surfaces. Enable for correct refraction rendering with"
" water-glass interfaces. Note: 'Mesh Around Obstacles'"
" should be enabled when using this feature",
default=False,
); exec(conv("invert_contact_normals"))
generate_motion_blur_data = BoolProperty(
)
generate_motion_blur_data: BoolProperty(
name="Generate Motion Blur Vectors",
description="Generate fluid surface speed vectors for motion blur"
" rendering. See documentation for limitations",
default=False,
); exec(conv("generate_motion_blur_data"))
enable_velocity_vector_attribute = BoolProperty(
)
enable_velocity_vector_attribute: BoolProperty(
name="Generate Velocity Attributes",
description="Generate fluid 3D velocity vector attributes for the fluid surface. After"
" baking, the velocity vectors (in m/s) can be accessed in a Cycles Attribute"
@@ -179,8 +178,8 @@ class DomainSurfaceProperties(bpy.types.PropertyGroup):
" direction is not needed, use Generate Speed Attributes instead",
default=False,
options={'HIDDEN'},
); exec(conv("enable_velocity_vector_attribute"))
enable_velocity_vector_attribute_against_obstacles = BoolProperty(
)
enable_velocity_vector_attribute_against_obstacles: BoolProperty(
name="Generate Against Obstacles",
description="Generate velocity-based attribute data against obstacles."
" Velocity-based attributes are the velocity/speed/vorticity attributes."
@@ -192,24 +191,24 @@ class DomainSurfaceProperties(bpy.types.PropertyGroup):
" in the render",
default=True,
options={'HIDDEN'},
); exec(conv("enable_velocity_vector_attribute_against_obstacles"))
enable_speed_attribute = BoolProperty(
)
enable_speed_attribute: BoolProperty(
name="Generate Speed Attributes",
description="Generate fluid speed attributes for the fluid surface. After"
" baking, the speed values (in m/s) can be accessed in a Cycles Attribute"
" Node or in Geometry Nodes with the name 'flip_speed' from the Fac output",
default=False,
options={'HIDDEN'},
); exec(conv("enable_speed_attribute"))
enable_vorticity_vector_attribute = BoolProperty(
)
enable_vorticity_vector_attribute: BoolProperty(
name="Generate Vorticity Attributes",
description="Generate fluid 3D vorticity vector attributes for the fluid surface. After"
" baking, the vorticity vectors can be accessed in a Cycles Attribute"
" Node or in Geometry Nodes with the name 'flip_vorticity' from the Vector output",
default=False,
options={'HIDDEN'},
); exec(conv("enable_vorticity_vector_attribute"))
enable_age_attribute = BoolProperty(
)
enable_age_attribute: BoolProperty(
name="Generate Age Attributes",
description="Generate fluid age attributes for the fluid surface."
" The age attribute starts at 0.0 when the liquid is spawned and counts up in"
@@ -217,8 +216,8 @@ class DomainSurfaceProperties(bpy.types.PropertyGroup):
" Node or in Geometry Nodes with the name 'flip_age' from the Fac output",
default=False,
options={'HIDDEN'},
); exec(conv("enable_age_attribute"))
age_attribute_radius = FloatProperty(
)
age_attribute_radius: FloatProperty(
name="Smoothing Radius",
description = "Amount of smoothing when transferring the age attribute to the surface mesh."
" Higher values result in smoother attribute transitions at the cost of simulation"
@@ -227,8 +226,8 @@ class DomainSurfaceProperties(bpy.types.PropertyGroup):
min=0.0,
default=3.0,
precision=1,
); exec(conv("age_attribute_radius"))
enable_lifetime_attribute = BoolProperty(
)
enable_lifetime_attribute: BoolProperty(
name="Generate Lifetime Attributes",
description="Generate fluid lifetime attributes for the fluid surface. This attribute allows the"
" fluid to start with a lifetime value that counts down in seconds and once the lifetime reaches 0,"
@@ -238,8 +237,8 @@ class DomainSurfaceProperties(bpy.types.PropertyGroup):
" the Fac output",
default=False,
options={'HIDDEN'},
); exec(conv("enable_lifetime_attribute"))
lifetime_attribute_radius = FloatProperty(
)
lifetime_attribute_radius: FloatProperty(
name="Smoothing Radius",
description = "Amount of smoothing when transferring the lifetime attribute to the surface mesh."
" Higher values result in smoother attribute transitions at the cost of simulation"
@@ -248,8 +247,8 @@ class DomainSurfaceProperties(bpy.types.PropertyGroup):
min=0.0,
default=3.0,
precision=1,
); exec(conv("lifetime_attribute_radius"))
lifetime_attribute_death_time = FloatProperty(
)
lifetime_attribute_death_time: FloatProperty(
name="Base Death Time",
description = "Base time in seconds at which fluid is removed from the simulation. At the default of 0.0,"
" fluid will be removed when their lifetime attribute counts down to 0.0. Increase or decrease this"
@@ -257,8 +256,8 @@ class DomainSurfaceProperties(bpy.types.PropertyGroup):
" Decreasing will result in fluid dying later",
default=0.0,
precision=2,
); exec(conv("lifetime_attribute_death_time"))
enable_whitewater_proximity_attribute = BoolProperty(
)
enable_whitewater_proximity_attribute: BoolProperty(
name="Whitewater Proximity Attributes",
description="Generate whitewater proximity attributes for the fluid surface. The attribute values represent"
" how many foam, bubble, or spray particles are near the surface mesh and can be used in a material to shade"
@@ -267,8 +266,8 @@ class DomainSurfaceProperties(bpy.types.PropertyGroup):
" and 'flip_spray_proximity' from the Fac output",
default=False,
options={'HIDDEN'},
); exec(conv("enable_whitewater_proximity_attribute"))
whitewater_proximity_attribute_radius = FloatProperty(
)
whitewater_proximity_attribute_radius: FloatProperty(
name="Smoothing Radius",
description = "Amount of smoothing when transferring the whitewater proximity attribute to the surface mesh."
" Higher values result in smoother attribute transitions at the cost of simulation"
@@ -277,8 +276,8 @@ class DomainSurfaceProperties(bpy.types.PropertyGroup):
min=0.0,
default=2.0,
precision=1,
); exec(conv("whitewater_proximity_attribute_radius"))
enable_color_attribute = BoolProperty(
)
enable_color_attribute: BoolProperty(
name="Generate Color Attributes",
description="Generate fluid color attributes for the fluid surface. Each"
" Inflow/Fluid object can set to assign color to the generated fluid. After"
@@ -287,8 +286,8 @@ class DomainSurfaceProperties(bpy.types.PropertyGroup):
" liquid effects",
default=False,
options={'HIDDEN'},
); exec(conv("enable_color_attribute"))
color_attribute_radius = FloatProperty(
)
color_attribute_radius: FloatProperty(
name="Smoothing Radius",
description = "Amount of smoothing when transferring the color attribute to the surface mesh."
" Higher values result in smoother attribute transitions at the cost of simulation"
@@ -297,14 +296,14 @@ class DomainSurfaceProperties(bpy.types.PropertyGroup):
min=0.0,
default=3.0,
precision=1,
); exec(conv("color_attribute_radius"))
enable_color_attribute_mixing = BoolProperty(
)
enable_color_attribute_mixing: BoolProperty(
name="Enable Mixing",
description="Simulate basic color mixing. If enabled, particles will absorb color attributes"
" from nearby particles. If disabled, particles will hold a static color value",
default=False,
); exec(conv("enable_color_attribute_mixing"))
color_attribute_mixing_rate = FloatProperty(
)
color_attribute_mixing_rate: FloatProperty(
name="Mixing Rate",
description = "Controls how quickly particles will absorb color from nearby particles. Higher"
" values will cause colors to mix and spread more quickly. Lower values will cause colors to"
@@ -313,8 +312,8 @@ class DomainSurfaceProperties(bpy.types.PropertyGroup):
min=0.0,
default=12,
precision=2,
); exec(conv("color_attribute_mixing_rate"))
color_attribute_mixing_radius = FloatProperty(
)
color_attribute_mixing_radius: FloatProperty(
name="Mixing Radius",
description = "Radius in which a particle can absorb color from nearby particles. Increasing"
" this value can result in smoother mixing transitions at the cost of simulation performance."
@@ -323,15 +322,15 @@ class DomainSurfaceProperties(bpy.types.PropertyGroup):
min=0.0,
default=1.0,
precision=2,
); exec(conv("color_attribute_mixing_radius"))
color_attribute_mixing_mode = EnumProperty(
)
color_attribute_mixing_mode: EnumProperty(
name="Mixing Mode",
description="Method of simulating color attribute mixing",
items=types.color_mixing_modes,
default='COLOR_MIXING_MODE_MIXBOX',
options={'HIDDEN'},
); exec(conv("color_attribute_mixing_mode"))
enable_source_id_attribute = BoolProperty(
)
enable_source_id_attribute: BoolProperty(
name="Generate Source ID Attributes",
description="Generate fluid source identifiers for the fluid surface. Each"
" Inflow/Fluid object can set to assign a source ID to the generated fluid. After"
@@ -341,43 +340,33 @@ class DomainSurfaceProperties(bpy.types.PropertyGroup):
" not supported with sheeting effects or resolution upscaling features",
default=False,
options={'HIDDEN'},
); exec(conv("enable_source_id_attribute"))
enable_viscosity_attribute = BoolProperty(
)
enable_viscosity_attribute: BoolProperty(
name="Enable Variable Viscosity",
description="Enable the variable viscosity solver for mixed viscosity simulations."
" After enabling, each Fluid/Inflow object can be set to assign a viscosity value"
" to the generated fluid. When enabled, viscosity value attributes will also"
" be generated for the fluid surface. After baking, the viscosity values can"
" be generated for the fluid surface and fluid particles. After baking, the viscosity values can"
" be accessed in a Cycles Attribute Node with the name 'flip_viscosity' from"
" the Fac output",
default=False,
options={'HIDDEN'},
); exec(conv("enable_viscosity_attribute"))
)
native_particle_scale = FloatProperty(default=3.0); exec(conv("native_particle_scale"))
default_cells_per_compute_chunk = FloatProperty(default=15.0); exec(conv("default_cells_per_compute_chunk")) # in millions
native_particle_scale: FloatProperty(default=3.0)
default_cells_per_compute_chunk: FloatProperty(default=15.0) # in millions
surface_mesh_expanded = BoolProperty(default=True); exec(conv("surface_mesh_expanded"))
meshing_volume_expanded = BoolProperty(default=False); exec(conv("meshing_volume_expanded"))
meshing_against_boundary_expanded = BoolProperty(default=False); exec(conv("meshing_against_boundary_expanded"))
meshing_against_obstacles_expanded = BoolProperty(default=False); exec(conv("meshing_against_obstacles_expanded"))
surface_display_settings_expanded = BoolProperty(default=False); exec(conv("surface_display_settings_expanded"))
geometry_attributes_expanded = BoolProperty(default=False); exec(conv("geometry_attributes_expanded"))
velocity_attributes_expanded = BoolProperty(default=False); exec(conv("velocity_attributes_expanded"))
color_attributes_expanded = BoolProperty(default=False); exec(conv("color_attributes_expanded"))
other_attributes_expanded = BoolProperty(default=False); exec(conv("other_attributes_expanded"))
show_smoothing_radius_in_ui: BoolProperty(default=False)
is_smoothing_radius_updated_to_default: BoolProperty(default=False)
show_smoothing_radius_in_ui = BoolProperty(default=False); exec(conv("show_smoothing_radius_in_ui"))
is_smoothing_radius_updated_to_default = BoolProperty(default=False); exec(conv("is_smoothing_radius_updated_to_default"))
preview_mode_attributes_tooltip = BoolProperty(
preview_mode_attributes_tooltip: BoolProperty(
name="Preview Mode Attributes Tooltip",
description="The fluid surface mesh is currently set to Preview Mode within the viewport and attributes"
" will not be loaded. Attributes will not be displayed correctly in viewport render mode."
" Surface attributes will only be loaded in Final Mode. The surface mesh display"
" mode can be set in the 'Domain > Display Settings' panel",
default=True,
); exec(conv("preview_mode_attributes_tooltip"))
)
def register_preset_properties(self, registry, path):
@@ -511,20 +500,12 @@ class DomainSurfaceProperties(bpy.types.PropertyGroup):
try:
# Cycles may not be enabled in the user's preferences
if vcu.is_blender_30():
obj.visible_camera = is_enabled
obj.visible_diffuse = is_enabled
obj.visible_glossy = is_enabled
obj.visible_transmission = is_enabled
obj.visible_volume_scatter = is_enabled
obj.visible_shadow = is_enabled
else:
obj.cycles_visibility.camera = is_enabled
obj.cycles_visibility.transmission = is_enabled
obj.cycles_visibility.diffuse = is_enabled
obj.cycles_visibility.scatter = is_enabled
obj.cycles_visibility.glossy = is_enabled
obj.cycles_visibility.shadow = is_enabled
obj.visible_camera = is_enabled
obj.visible_diffuse = is_enabled
obj.visible_glossy = is_enabled
obj.visible_transmission = is_enabled
obj.visible_volume_scatter = is_enabled
obj.visible_shadow = is_enabled
except:
pass
@@ -33,35 +33,34 @@ from ..objects import flip_fluid_cache
class DomainWhitewaterProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
whitewater_ui_mode = EnumProperty(
whitewater_ui_mode: EnumProperty(
name="Whitewater UI Mode",
description="Whitewater UI mode",
items=types.whitewater_ui_modes,
default='WHITEWATER_UI_MODE_BASIC',
); exec(conv("whitewater_ui_mode"))
highlight_advanced_settings = BoolProperty(
)
highlight_advanced_settings: BoolProperty(
name="Highlight Advanced Settings",
description="Highlight advanced parameters in red",
default=True,
); exec(conv("highlight_advanced_settings"))
enable_whitewater_simulation = BoolProperty(
)
enable_whitewater_simulation: BoolProperty(
name="Enable Whitewater Simulation",
description="Enable whitewater foam/bubble/spray particle solver",
default=False,
update=lambda self, context: self._update_enable_whitewater_simulation(context),
options={'HIDDEN'},
); exec(conv("enable_whitewater_simulation"))
enable_foam = BoolProperty(
)
enable_foam: BoolProperty(
name="Foam",
description="Enable solving for foam particles. Foam particles form"
" a layer on the fluid surface and are advected with the fluid"
" velocity. If disabled, any particles that enter the foam layer"
" will be destroyed",
default=True,
); exec(conv("enable_foam"))
enable_bubbles = BoolProperty(
)
enable_bubbles: BoolProperty(
name = "Bubbles",
description="Enable solving for bubble particles. Bubble particles"
" below the foam layer are advected with the fluid velocity and"
@@ -70,30 +69,30 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
" particles are a large contributor to the foam layer and"
" disabling may severely limit the amount of generated foam",
default=True,
); exec(conv("enable_bubbles"))
enable_spray = BoolProperty(
)
enable_spray: BoolProperty(
name="Spray",
description="Enable solving for spray particles. Spray particles"
" above the foam layer are simulated ballistically with"
" gravity. If disabled, any particles that move above the foam"
" layer will be destroyed",
default=True,
); exec(conv("enable_spray"))
enable_dust = BoolProperty(
)
enable_dust: BoolProperty(
name="Dust",
description="Enable solving for dust particles. Dust particles are"
" generated near obstacle surfaces and are advected with the"
" fluid velocity while sinking towards the ground. If disabled,"
" these particles will not be generated",
default=False,
); exec(conv("enable_dust"))
generate_whitewater_motion_blur_data = BoolProperty(
)
generate_whitewater_motion_blur_data: BoolProperty(
name="Generate Motion Blur Vectors",
description="Generate whitewater speed vectors for motion blur"
" rendering",
default=False,
); exec(conv("generate_whitewater_motion_blur_data"))
enable_velocity_vector_attribute = BoolProperty(
)
enable_velocity_vector_attribute: BoolProperty(
name="Generate Velocity Attributes",
description="Generate fluid 3D velocity vector attributes for whitewater particles. After"
" baking, the velocity vectors (in m/s) can be accessed in a Cycles Attribute"
@@ -101,8 +100,8 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
" instanced particles, only supported on pointclouds",
default=False,
options={'HIDDEN'},
); exec(conv("enable_velocity_vector_attribute"))
enable_id_attribute = BoolProperty(
)
enable_id_attribute: BoolProperty(
name="Generate ID Attributes",
description="Generate stable ID attributes for whitewater particles. After"
" baking, the ID values can be accessed in a Cycles Attribute"
@@ -111,8 +110,8 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
" size or color. Not supported on instanced particles, only supported on pointclouds",
default=True,
options={'HIDDEN'},
); exec(conv("enable_id_attribute"))
enable_lifetime_attribute = BoolProperty(
)
enable_lifetime_attribute: BoolProperty(
name="Generate Lifetime Attributes",
description="Generate remaining lifetime attributes for whitewater particles. After"
" baking, the lifetime values can be accessed in a Cycles Attribute Node or in"
@@ -121,21 +120,21 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
" only supported on pointclouds",
default=False,
options={'HIDDEN'},
); exec(conv("enable_lifetime_attribute"))
enable_whitewater_emission = bpy.props.BoolProperty(
)
enable_whitewater_emission: bpy.props.BoolProperty(
name="Enable Whitewater Emission",
description="Allow whitewater emitters to generate new particles",
default=True,
); exec(conv("enable_whitewater_emission"))
whitewater_emitter_generation_rate = IntProperty(
)
whitewater_emitter_generation_rate: IntProperty(
name="Emitter Generation Rate (Percent)",
description="Controls how many whitewater emitters are generated."
" Emitters are generated at wavecrests and in areas high"
" turbulence where fluid is likely to be aerated",
min=0, max=100,
default=100,
); exec(conv("whitewater_emitter_generation_rate"))
wavecrest_emission_rate = FloatProperty(
)
wavecrest_emission_rate: FloatProperty(
name="Max Wavecrest Emission Rate",
description="Maximum number of whitewater particles that a"
" single wavecrest emitter may generate per simulation second",
@@ -143,8 +142,8 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
default=175,
step=30,
precision=0,
); exec(conv("wavecrest_emission_rate"))
turbulence_emission_rate = FloatProperty(
)
turbulence_emission_rate: FloatProperty(
name="Max Turbulence Emission Rate",
description="Maximum number of whitewater particles that a"
" single turbulence emitter may generate per simulation second",
@@ -152,8 +151,8 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
default=175,
step=30,
precision=0,
); exec(conv("turbulence_emission_rate"))
dust_emission_rate = FloatProperty(
)
dust_emission_rate: FloatProperty(
name="Max Dust Emission Rate",
description="Maximum number of dust particles that a"
" single dust emitter may generate per simulation second",
@@ -161,16 +160,16 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
default=175,
step=30,
precision=0,
); exec(conv("dust_emission_rate"))
spray_emission_speed = FloatProperty(
)
spray_emission_speed: FloatProperty(
name="Spray Emission Speed",
description="Speed scaling factor for spray particle emission. Increasing"
" this value will generate more spread out and exaggerated spray effects",
min=0.0, soft_min=1.0,
soft_max=3.0,
default=1.2,
); exec(conv("spray_emission_speed"))
min_max_whitewater_energy_speed = NewMinMaxFloatProperty(
)
min_max_whitewater_energy_speed: NewMinMaxFloatProperty(
name_min="Min Energy Speed",
description_min="Fluid with speed less than this value will generate"
" no whitewater",
@@ -185,8 +184,8 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
min_max=0,
default_max=3.0,
precision_max=2,
); exec(conv("min_max_whitewater_energy_speed"))
min_max_whitewater_wavecrest_curvature = NewMinMaxFloatProperty(
)
min_max_whitewater_wavecrest_curvature: NewMinMaxFloatProperty(
name_min="Min Curvature",
description_min="Wavecrests with curvature less than this value will"
" generate no whitewater. This value rarely needs to be changed",
@@ -202,8 +201,8 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
min_max=0.0, max_max=5.0,
default_max=1.0,
precision_max=2,
); exec(conv("min_max_whitewater_wavecrest_curvature"))
min_max_whitewater_turbulence = NewMinMaxFloatProperty(
)
min_max_whitewater_turbulence: NewMinMaxFloatProperty(
name_min="Min Turbulence",
description_min="Fluid with turbulence less than this value will"
" generate no whitewater. This value rarely needs to be changed",
@@ -219,8 +218,8 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
min_max=0,
default_max=200,
precision_max=0,
); exec(conv("min_max_whitewater_turbulence"))
max_whitewater_particles = FloatProperty(
)
max_whitewater_particles: FloatProperty(
name="Max Particles (in millions)",
description="Maximum number of whitewater particles (in millions)"
" to simulate. The solver will stop generating new whitewater"
@@ -231,20 +230,20 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
min=0, max=357,
default=12,
precision=2,
); exec(conv("max_whitewater_particles"))
enable_whitewater_emission_near_boundary = BoolProperty(
)
enable_whitewater_emission_near_boundary: BoolProperty(
name="Enable Emission Near Domain Boundary",
description="Allow whitewater emitters to generate particles at"
" the domain boundary",
default=False,
); exec(conv("enable_whitewater_emission_near_boundary"))
enable_dust_emission_near_boundary = BoolProperty(
)
enable_dust_emission_near_boundary: BoolProperty(
name="Enable Dust Emission Near Domain Boundary",
description="Allow whitewater emitters to generate dust particles near"
" the domain floor",
default=False,
); exec(conv("enable_dust_emission_near_boundary"))
min_max_whitewater_lifespan = NewMinMaxFloatProperty(
)
min_max_whitewater_lifespan: NewMinMaxFloatProperty(
name_min="Min Lifespan",
description_min="Minimum whitewater particle lifespan in seconds",
min_min=0.0,
@@ -256,44 +255,44 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
min_max=0.0,
default_max=6.0,
precision_max=2,
); exec(conv("min_max_whitewater_lifespan"))
whitewater_lifespan_variance = FloatProperty(
)
whitewater_lifespan_variance: FloatProperty(
name="Lifespan Variance",
description ="A random number of seconds in this range will be added"
" or subtracted from the whitewater particle lifespan",
min=0.0,
default=3.0,
precision=2,
); exec(conv("whitewater_lifespan_variance"))
foam_lifespan_modifier = FloatProperty(
)
foam_lifespan_modifier: FloatProperty(
name="Foam Lifespan Modifier",
description="Multiply the lifespan of a foam particle by this value",
min=0.0,
default=1.0,
precision=1,
); exec(conv("foam_lifespan_modifier"))
bubble_lifespan_modifier = FloatProperty(
)
bubble_lifespan_modifier: FloatProperty(
name="Bubble Lifespan Modifier",
description="Multiply the lifespan of a bubble particle by this value",
min=0.0,
default=4.0,
precision=1,
); exec(conv("bubble_lifespan_modifier"))
spray_lifespan_modifier = FloatProperty(
)
spray_lifespan_modifier: FloatProperty(
name="Spray Lifespan Modifier",
description="Multiply the lifespan of a spray particle by this value",
min=0.0,
default=5.0,
precision=1,
); exec(conv("spray_lifespan_modifier"))
dust_lifespan_modifier = FloatProperty(
)
dust_lifespan_modifier: FloatProperty(
name="Dust Lifespan Modifier",
description="Multiply the lifespan of a dust particle by this value",
min=0.0,
default=2.0,
precision=1,
); exec(conv("dust_lifespan_modifier"))
foam_advection_strength = FloatProperty(
)
foam_advection_strength: FloatProperty(
name="Foam Advection Strength",
description="Controls how much the foam moves along with the motion"
" of the fluid surface. High values cause tighter streaks of"
@@ -303,8 +302,8 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
default=1.0,
precision=2,
subtype='FACTOR',
); exec(conv("foam_advection_strength"))
foam_layer_depth = FloatProperty(
)
foam_layer_depth: FloatProperty(
name="Foam Layer Depth",
description="Set the thickness of the whitewater foam layer",
min=0.0,
@@ -312,8 +311,8 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
default=0.4,
precision=2,
subtype='FACTOR',
); exec(conv("foam_layer_depth"))
foam_layer_offset = FloatProperty(
)
foam_layer_offset: FloatProperty(
name="Foam Layer Offset",
description="Set the offset of the whitewater foam layer above/below"
" the fluid surface. If set to a value of 1, the foam layer will"
@@ -324,15 +323,15 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
default=0.25,
precision=2,
subtype='FACTOR',
); exec(conv("foam_layer_offset"))
preserve_foam = BoolProperty(
)
preserve_foam: BoolProperty(
name="Preserve Foam",
description="Increase the lifespan of foam particles based on the"
" local density of foam particles, which can help create clumps"
" and streaks of foam on the liquid surface over time",
default=True,
); exec(conv("preserve_foam"))
foam_preservation_rate = FloatProperty(
)
foam_preservation_rate: FloatProperty(
name="Foam Preservation Rate",
description="Rate to add to the lifetime of preserved foam. This"
" value is the number of seconds to add per second, so if"
@@ -340,8 +339,8 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
" clumps from every being killed",
default=0.75,
precision=2,
); exec(conv("foam_preservation_rate"))
min_max_foam_density = NewMinMaxIntProperty(
)
min_max_foam_density: NewMinMaxIntProperty(
name_min="Min Foam Density",
description_min="Foam densities less than this value will not increase"
" the lifetime of a foam particle. Foam density units are in"
@@ -356,8 +355,8 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
" density units are in number of particles per voxel",
min_max=0,
default_max=45,
); exec(conv("min_max_foam_density"))
bubble_drag_coefficient = FloatProperty(
)
bubble_drag_coefficient: FloatProperty(
name="Bubble Drag Coefficient",
description="Controls how quickly bubble particles are dragged with"
" the fluid velocity. If set to 1, bubble particles will be"
@@ -366,8 +365,8 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
default=0.8,
precision=2,
subtype='FACTOR',
); exec(conv("bubble_drag_coefficient"))
bubble_bouyancy_coefficient = FloatProperty(
)
bubble_bouyancy_coefficient: FloatProperty(
name="Bubble Buoyancy Coefficient",
description="Controls how quickly bubble particles float towards"
" the fluid surface. If set to a negative value, bubbles will"
@@ -375,15 +374,15 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
default=2.5,
precision=2,
step=0.3,
); exec(conv("bubble_bouyancy_coefficient"))
spray_drag_coefficient = FloatProperty(
)
spray_drag_coefficient: FloatProperty(
name="Spray Drag Coefficient",
description="Controls amount of air resistance on a spray particle",
min=0.0, max=5.0,
default=3.0,
precision=2,
); exec(conv("spray_drag_coefficient"))
dust_drag_coefficient = FloatProperty(
)
dust_drag_coefficient: FloatProperty(
name="Dust Drag Coefficient",
description="Controls how quickly dust particles are dragged with"
" the fluid velocity. If set to 1, dust particles will be"
@@ -392,8 +391,8 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
default=0.75,
precision=2,
subtype='FACTOR',
); exec(conv("dust_drag_coefficient"))
dust_bouyancy_coefficient = FloatProperty(
)
dust_bouyancy_coefficient: FloatProperty(
name="Dust Buoyancy Coefficient",
description="Controls how quickly dust particles sink towards"
" the ground. Decreasing this value will cause particles to sink"
@@ -402,86 +401,86 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
default=-3.0,
precision=2,
step=0.3,
); exec(conv("dust_bouyancy_coefficient"))
foam_boundary_behaviour = EnumProperty(
)
foam_boundary_behaviour: EnumProperty(
name="Foam Behaviour At Limits",
description="Specifies the foam particle behavior when hitting the"
" domain boundary",
items=types.boundary_behaviours,
default='BEHAVIOUR_COLLIDE',
); exec(conv("foam_boundary_behaviour"))
bubble_boundary_behaviour = EnumProperty(
)
bubble_boundary_behaviour: EnumProperty(
name="Bubble Behaviour At Limits",
description="Specifies the bubble particle behavior when hitting"
" the domain boundary",
items=types.boundary_behaviours,
default='BEHAVIOUR_COLLIDE',
); exec(conv("bubble_boundary_behaviour"))
spray_boundary_behaviour = EnumProperty(
)
spray_boundary_behaviour: EnumProperty(
name="Spray Behaviour At Limits",
description="Specifies the spray particle behavior when hitting the"
" domain boundary",
items=types.boundary_behaviours,
default='BEHAVIOUR_COLLIDE',
); exec(conv("spray_boundary_behaviour"))
foam_boundary_active = BoolVectorProperty(
)
foam_boundary_active: BoolVectorProperty(
name="",
description="Activate behaviour on the corresponding side of the domain",
default=(True, True, True, True, False, True),
size=6,
); exec(conv("foam_boundary_active"))
bubble_boundary_active = BoolVectorProperty(
)
bubble_boundary_active: BoolVectorProperty(
name="",
description="Activate behaviour on the corresponding side of the domain",
default=(True, True, True, True, False, True),
size=6,
); exec(conv("bubble_boundary_active"))
spray_boundary_active = BoolVectorProperty(
)
spray_boundary_active: BoolVectorProperty(
name="",
description="Activate behaviour on the corresponding side of the domain",
default=(True, True, True, True, False, True),
size=6,
); exec(conv("spray_boundary_active"))
whitewater_boundary_collisions_mode = EnumProperty(
)
whitewater_boundary_collisions_mode: EnumProperty(
name="Domain Boundary Collisions Mode",
description="Select how to set the domain boundary collisions",
items=types.boundary_collisions_modes,
default='BOUNDARY_COLLISIONS_MODE_INHERIT',
options={'HIDDEN'},
); exec(conv("whitewater_boundary_collisions_mode"))
foam_boundary_collisions = BoolVectorProperty(
)
foam_boundary_collisions: BoolVectorProperty(
name="",
description="Enable collisions on the corresponding side of the domain for whitewater foam particles."
" If disabled, this side of the boundary will be open and will act"
" as an outflow",
default=(True, True, True, True, True, True),
size=6,
); exec(conv("foam_boundary_collisions"))
bubble_boundary_collisions = BoolVectorProperty(
)
bubble_boundary_collisions: BoolVectorProperty(
name="",
description="Enable collisions on the corresponding side of the domain for whitewater bubble particles."
" If disabled, this side of the boundary will be open and will act"
" as an outflow",
default=(True, True, True, True, True, True),
size=6,
); exec(conv("bubble_boundary_collisions"))
spray_boundary_collisions = BoolVectorProperty(
)
spray_boundary_collisions: BoolVectorProperty(
name="",
description="Enable collisions on the corresponding side of the domain for whitewater spray particles."
" If disabled, this side of the boundary will be open and will act"
" as an outflow",
default=(True, True, True, True, True, True),
size=6,
); exec(conv("spray_boundary_collisions"))
dust_boundary_collisions = BoolVectorProperty(
)
dust_boundary_collisions: BoolVectorProperty(
name="",
description="Enable collisions on the corresponding side of the domain for whitewater dust particles."
" If disabled, this side of the boundary will be open and will act"
" as an outflow",
default=(True, True, True, True, True, True),
size=6,
); exec(conv("dust_boundary_collisions"))
obstacle_influence_base_level = FloatProperty(
)
obstacle_influence_base_level: FloatProperty(
name="Influence Base Level",
description="The default value of whitewater influence. If a location"
" is not affected by an obstacle's influence, the amount"
@@ -492,8 +491,8 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
min=0.0,
default=1.0,
precision=2,
); exec(conv("obstacle_influence_base_level"))
obstacle_influence_decay_rate = FloatProperty(
)
obstacle_influence_decay_rate: FloatProperty(
name="Influence Decay Rate",
description="The rate at which influence will decay towards the"
" base level. If a keyframed/animated obstacle leaves an"
@@ -504,16 +503,7 @@ class DomainWhitewaterProperties(bpy.types.PropertyGroup):
min=0.0,
default=5.0,
precision=2,
); exec(conv("obstacle_influence_decay_rate"))
settings_view_mode_expanded = BoolProperty(default=False); exec(conv("settings_view_mode_expanded"))
whitewater_simulation_particles_expanded = BoolProperty(default=False); exec(conv("whitewater_simulation_particles_expanded"))
emitter_settings_expanded = BoolProperty(default=True); exec(conv("emitter_settings_expanded"))
particle_settings_expanded = BoolProperty(default=False); exec(conv("particle_settings_expanded"))
boundary_behaviour_settings_expanded = BoolProperty(default=False); exec(conv("boundary_behaviour_settings_expanded"))
obstacle_settings_expanded = BoolProperty(default=False); exec(conv("obstacle_settings_expanded"))
whitewater_display_settings_expanded = BoolProperty(default=False); exec(conv("whitewater_display_settings_expanded"))
geometry_attributes_expanded = BoolProperty(default=False); exec(conv("geometry_attributes_expanded"))
)
def register_preset_properties(self, registry, path):
@@ -30,16 +30,15 @@ from ..objects.flip_fluid_aabb import AABB
class DomainWorldProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
world_scale_mode = EnumProperty(
world_scale_mode: EnumProperty(
name="World Scaling Mode",
description="Scaling mode for the physical size of the domain",
items=types.world_scale_mode,
default='WORLD_SCALE_MODE_RELATIVE',
options={'HIDDEN'},
); exec(conv("world_scale_mode"))
world_scale_relative = FloatProperty(
)
world_scale_relative: FloatProperty(
name="Meters",
description="Size of a Blender unit in meters. If set to 1.0, each blender unit will be equal to 1.0 meter in the simulation",
min=0.0001,
@@ -47,8 +46,8 @@ class DomainWorldProperties(bpy.types.PropertyGroup):
precision=3,
update=lambda self, context: self._update_world_scale_relative(context),
options={'HIDDEN'},
); exec(conv("world_scale_relative"))
world_scale_absolute = FloatProperty(
)
world_scale_absolute: FloatProperty(
name="Meters",
description="Size of the longest side of the domain in meters",
min=0.001,
@@ -56,23 +55,23 @@ class DomainWorldProperties(bpy.types.PropertyGroup):
precision=3,
update=lambda self, context: self._update_world_scale_absolute(context),
options={'HIDDEN'},
); exec(conv("world_scale_absolute"))
gravity_type = EnumProperty(
)
gravity_type: EnumProperty(
name="Gravity Type",
description="Gravity Type",
items=types.gravity_types,
default='GRAVITY_TYPE_SCENE',
options={'HIDDEN'},
); exec(conv("gravity_type"))
gravity = FloatVectorProperty(
)
gravity: FloatVectorProperty(
name="Gravity",
description="Gravity in X, Y, and Z direction",
default=(0.0, 0.0, -9.81),
precision=3,
size=3,
subtype='ACCELERATION',
); exec(conv("gravity"))
force_field_resolution = EnumProperty(
)
force_field_resolution: EnumProperty(
name="Force Field Resolution",
description="Amount of grid resolution to use when evaluating force fields."
" Higher resolution improves force field accuracy at the cost of speed"
@@ -82,18 +81,18 @@ class DomainWorldProperties(bpy.types.PropertyGroup):
items=types.force_field_resolution_modes,
default='FORCE_FIELD_RESOLUTION_ULTRA',
options={'HIDDEN'},
); exec(conv("force_field_resolution"))
force_field_weight_fluid_particles = FloatProperty(
)
force_field_weight_fluid_particles: FloatProperty(
name="Fluid Particles",
description="Force field object weight for fluid particles",
description="Global force field weight for fluid particles. Applies to all force field objects",
soft_min=0.0,
soft_max=1.0,
default=1.0,
precision=3,
); exec(conv("force_field_weight_fluid_particles"))
force_field_weight_whitewater_foam = FloatProperty(
)
force_field_weight_whitewater_foam: FloatProperty(
name="Whitewater Foam",
description="Force field object weight for whitewater foam particles. Note: This setting"
description="Global force field weight for whitewater foam particles. Applies to all force field objects. Note: This setting"
" currently has no effect on the simulation. The movement of foam particles is"
" controlled only by the motion of the fluid surface. Force fields and gravity"
" currently have no effect on foam particles",
@@ -101,10 +100,10 @@ class DomainWorldProperties(bpy.types.PropertyGroup):
soft_max=1.0,
default=1.0,
precision=3,
); exec(conv("force_field_weight_whitewater_foam"))
force_field_weight_whitewater_bubble = FloatProperty(
)
force_field_weight_whitewater_bubble: FloatProperty(
name="Whitewater Bubble",
description="Force field object weight for whitewater bubble particles. Note: Bubble particles"
description="Global force field weight for whitewater bubble particles. Applies to all force field objects. Note: Bubble particles"
" are assumed to be lower density than the containing liquid and due to buoyancy, bubbles"
" will drift the opposite direction of the force fields. If you desire bubble particles"
" to move with the direction of the force fields, set this weight to a negative value",
@@ -112,45 +111,45 @@ class DomainWorldProperties(bpy.types.PropertyGroup):
soft_max=1.0,
default=1.0,
precision=3,
); exec(conv("force_field_weight_whitewater_bubble"))
force_field_weight_whitewater_spray = FloatProperty(
)
force_field_weight_whitewater_spray: FloatProperty(
name="Whitewater Spray",
description="Force field object weight for whitewater spray particles. Tip: Spray particles are"
description="Global force field weight for whitewater spray particles. Applies to all force field objects. Tip: Spray particles are"
" often lower a lower density than the fluid. Depending on the desired effect, setting a higher"
" weight value can be a good choice",
soft_min=0.0,
soft_max=1.0,
default=1.0,
precision=3,
); exec(conv("force_field_weight_whitewater_spray"))
force_field_weight_whitewater_dust = FloatProperty(
)
force_field_weight_whitewater_dust: FloatProperty(
name="Whitewater Dust",
description="Force field object weight for whitewater dust particles",
description="Global force field weight for whitewater dust particles. Applies to all force field objects",
soft_min=0.0,
soft_max=1.0,
default=1.0,
precision=3,
); exec(conv("force_field_weight_whitewater_dust"))
force_field_resolution_tooltip = BoolProperty(
)
force_field_resolution_tooltip: BoolProperty(
name="Force Field Grid Resolution",
description="Exact force field grid resolution calculated from the domain"
" resolution. See Debug Panel for force field visualization tools",
default=True,
); exec(conv("force_field_resolution_tooltip"))
enable_viscosity = BoolProperty(
)
enable_viscosity: BoolProperty(
name="Enable Viscosity",
description="Enable viscosity solver",
default=False,
); exec(conv("enable_viscosity"))
viscosity = FloatProperty(
)
viscosity: FloatProperty(
name="Viscosity",
description="Viscosity base value. This value is multipled by 10 to the"
" power of (exponent * -1)",
min=0.0,
default=5.0,
precision=3,
); exec(conv("viscosity"))
viscosity_exponent = IntProperty(
)
viscosity_exponent: IntProperty(
name="Viscosity Exponent",
description="Viscosity exponent. Negative exponent for the viscosity value"
" to simplify entering small values (ex: 5.0 * 10^-3 = 0.005)",
@@ -159,8 +158,8 @@ class DomainWorldProperties(bpy.types.PropertyGroup):
default=0,
update=lambda self, context: self._update_viscosity_exponent(context),
options={'HIDDEN'},
); exec(conv("viscosity_exponent"))
viscosity_solver_error_tolerance = IntProperty(
)
viscosity_solver_error_tolerance: IntProperty(
description="Accuracy of the viscosity solver. Decrease to speed up baking at the cost of accuracy,"
" increase to improve accuracy at the cost of baking speed. High viscosity thick or stiff fluids"
" benefit the most from increasing accuracy. Low viscosity thin fluids often work well at the lowest"
@@ -169,21 +168,21 @@ class DomainWorldProperties(bpy.types.PropertyGroup):
min=1, max=6,
soft_max=4,
default=4,
); exec(conv("viscosity_solver_error_tolerance"))
enable_surface_tension = BoolProperty(
)
enable_surface_tension: BoolProperty(
name="Enable Surface Tension",
description="Enable surface tension forces",
default=False,
); exec(conv("enable_surface_tension"))
surface_tension = FloatProperty(
)
surface_tension: FloatProperty(
name="Surface Tension",
description="Surface tension base value. This value is multipled by 10 to the"
" power of (exponent * -1)",
min=0.0,
default=0.25,
precision=3,
); exec(conv("surface_tension"))
surface_tension_exponent = IntProperty(
)
surface_tension_exponent: IntProperty(
name="Viscosity Exponent",
description="Viscosity exponent. Negative exponent for the surface tension value"
" to simplify entering small values (ex: 5.0 * 10^-3 = 0.005)",
@@ -192,8 +191,8 @@ class DomainWorldProperties(bpy.types.PropertyGroup):
default=0,
update=lambda self, context: self._update_surface_tension_exponent(context),
options={'HIDDEN'},
); exec(conv("surface_tension_exponent"))
surface_tension_accuracy = IntProperty(
)
surface_tension_accuracy: IntProperty(
name="Surface Tension Accuracy",
description="Amount of accuracy when calculating surface tension."
" Increasing accuracy will produce more accurate surface tension"
@@ -202,15 +201,15 @@ class DomainWorldProperties(bpy.types.PropertyGroup):
min=0, max=100,
default=95,
subtype='PERCENTAGE',
); exec(conv("surface_tension_accuracy"))
surface_tension_solver_method = EnumProperty(
)
surface_tension_solver_method: EnumProperty(
name="Surface Tension Solver",
description="Surface tension solving method to use",
items=types.surface_tension_solver_methods,
default='SURFACE_TENSION_SOLVER_METHOD_REGULAR',
options={'HIDDEN'},
); exec(conv("surface_tension_solver_method"))
enable_sheet_seeding = BoolProperty(
)
enable_sheet_seeding: BoolProperty(
name="Enable Sheeting Effects",
description="Fluid sheeting fills in gaps between fluid particles to"
" help preserve thin fluid sheets and splashes. Tip: Sheeting will"
@@ -218,8 +217,8 @@ class DomainWorldProperties(bpy.types.PropertyGroup):
" fluid volume. Keyframing the Sheeting Strength down to 0.0 when no longer"
" needed can help prevent increased volume",
default=False,
); exec(conv("enable_sheet_seeding"))
sheet_fill_rate = FloatProperty(
)
sheet_fill_rate: FloatProperty(
name="Sheeting Strength",
description="The rate at which new sheeting particles are added."
" A higher value will add sheeting particles more often and"
@@ -227,16 +226,27 @@ class DomainWorldProperties(bpy.types.PropertyGroup):
min=0.0, max=1.0,
default=0.5,
precision=2,
); exec(conv("sheet_fill_rate"))
sheet_fill_threshold = FloatProperty(
)
sheet_fill_threshold: FloatProperty(
name="Sheeting Thickness",
description="Controls how thick to fill in gaps",
min=0.0, max=1.0,
soft_min=0.05,
default=0.1,
precision=2,
); exec(conv("sheet_fill_threshold"))
boundary_friction = FloatProperty(
)
enable_density_attribute: BoolProperty(
name="Enable Variable Density",
description="Enable the variable density solver for mixed density simulations."
" After enabling, each Fluid/Inflow object can be set to assign a density value"
" to the generated fluid. When enabled, density value attributes will also"
" be generated for the fluid surface and fluid particles. After baking, the density values can"
" be accessed in a Cycles Attribute Node with the name 'flip_density' from"
" the Fac output",
default=False,
options={'HIDDEN'},
)
boundary_friction: FloatProperty(
name="Boundary Friction",
description="Amount of friction on the domain boundary walls",
min=0.0,
@@ -244,21 +254,14 @@ class DomainWorldProperties(bpy.types.PropertyGroup):
default=0.0,
precision=2,
subtype='FACTOR',
); exec(conv("boundary_friction"))
)
last_viscosity_exponent = IntProperty(default=0)
exec(conv("last_viscosity_exponent"))
last_viscosity_exponent: IntProperty(default=0)
last_surface_tension_exponent: IntProperty(default=0)
native_surface_tension_scale: FloatProperty(default=0.1)
minimum_surface_tension_substeps: IntProperty(default=-1)
last_surface_tension_exponent = IntProperty(default=0)
exec(conv("last_surface_tension_exponent"))
native_surface_tension_scale = FloatProperty(default=0.1)
exec(conv("native_surface_tension_scale"))
minimum_surface_tension_substeps = IntProperty(default=-1)
exec(conv("minimum_surface_tension_substeps"))
surface_tension_substeps_tooltip = BoolProperty(
surface_tension_substeps_tooltip: BoolProperty(
name="Estimated Substeps",
description="The estimated number of substeps per frame that the"
" simulator will run in order to keep simulation stable during surface"
@@ -266,30 +269,19 @@ class DomainWorldProperties(bpy.types.PropertyGroup):
" and size, framerate, amount of surface tension, and surface tension"
" accuracy",
default=True,
); exec(conv("surface_tension_substeps_tooltip"))
)
surface_tension_substeps_exceeded_tooltip = BoolProperty(
surface_tension_substeps_exceeded_tooltip: BoolProperty(
name="Warning: Too Many Substeps",
description="The estimated number of Surface Tension substeps per frame exceeds the Max Frame"
" Substeps value. This can cause an unstable simulation. Either decrease the amount of"
" Surface Tension in the FLIP Fluid World panel to lower the number of required substeps or"
" increase the number of allowed Max Frame Substeps in the FLIP Fluid Advanced panel",
default=True,
); exec(conv("surface_tension_substeps_exceeded_tooltip"))
)
minimum_surface_tension_cfl = FloatProperty(default=0.25)
exec(conv("minimum_surface_tension_cfl"))
maximum_surface_tension_cfl = FloatProperty(default=5.0)
exec(conv("maximum_surface_tension_cfl"))
world_scale_settings_expanded = BoolProperty(default=True); exec(conv("world_scale_settings_expanded"))
force_field_settings_expanded = BoolProperty(default=False); exec(conv("force_field_settings_expanded"))
viscosity_settings_expanded = BoolProperty(default=False); exec(conv("viscosity_settings_expanded"))
surface_tension_settings_expanded = BoolProperty(default=False); exec(conv("surface_tension_settings_expanded"))
sheeting_settings_expanded = BoolProperty(default=False); exec(conv("sheeting_settings_expanded"))
friction_settings_expanded = BoolProperty(default=False); exec(conv("friction_settings_expanded"))
obstacle_friction_expanded = BoolProperty(default=False); exec(conv("obstacle_friction_expanded"))
minimum_surface_tension_cfl: FloatProperty(default=0.25)
maximum_surface_tension_cfl: FloatProperty(default=5.0)
def scene_update_post(self, scene):
@@ -327,6 +319,7 @@ class DomainWorldProperties(bpy.types.PropertyGroup):
add(path + ".enable_sheet_seeding", "Enable Sheeting Effects", group_id=0)
add(path + ".sheet_fill_rate", "Sheeting Strength", group_id=0)
add(path + ".sheet_fill_threshold", "Sheeting Thickness", group_id=0)
add(path + ".enable_density_attribute", "Enable Variable Density", group_id=0)
add(path + ".boundary_friction", "Boundary Friction", group_id=0)
@@ -25,22 +25,21 @@ from ..utils import version_compatibility_utils as vcu
class FlipFluidProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
show_render = BoolProperty(
show_render: BoolProperty(
name="Show Render",
description="Display simulation in render. If disabled, simulation data will not be loaded in the render",
default=True,
); exec(conv("show_render"))
show_viewport = BoolProperty(
)
show_viewport: BoolProperty(
name="Show Viewport",
description="Display simulation in viewport. If disabled, simulation data will not be loaded in the viewport."
" Disable to speed up playback while working on other areas of your scene",
default=True,
); exec(conv("show_viewport"))
)
logo_name = StringProperty("flip_fluids_logo"); exec(conv("logo_name"))
domain_object_name = StringProperty(default=""); exec(conv("domain_object_name"))
logo_name: StringProperty("flip_fluids_logo")
domain_object_name: StringProperty(default="")
@classmethod
@@ -242,10 +241,7 @@ class FlipFluidProperties(bpy.types.PropertyGroup):
def _initialize_custom_icons(self):
addon_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if vcu.is_blender_28():
icon_filename = "flip_fluids_logo_28.png"
else:
icon_filename = "flip_fluids_logo_27.png"
icon_filename = "flip_fluids_logo_28.png"
logo_path = os.path.join(addon_dir, "icons", icon_filename)
self.custom_icons.clear()
if os.path.isfile(logo_path):
@@ -31,23 +31,22 @@ from ..utils import version_compatibility_utils as vcu
class FlipFluidFluidProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
initial_velocity = FloatVectorProperty(
initial_velocity: FloatVectorProperty(
name="Initial Velocity",
description="Initial velocity of fluid (m/s)",
default =(0.0, 0.0, 0.0),
size=3,
precision=3,
subtype='VELOCITY',
); exec(conv("initial_velocity"))
append_object_velocity = BoolProperty(
)
append_object_velocity: BoolProperty(
name="Add Object Velocity to Fluid",
description="Add the velocity of the object to the initial velocity"
" of the fluid. Object mesh must be rigid (non-deformable)",
default=False,
); exec(conv("append_object_velocity"))
append_object_velocity_influence = FloatProperty(
)
append_object_velocity_influence: FloatProperty(
name="Influence",
description="Amount of velocity that is added to the fluid."
" A value of 1.0 is normal, less than 1.0 will dampen the"
@@ -57,8 +56,8 @@ class FlipFluidFluidProperties(bpy.types.PropertyGroup):
soft_min=0.0, soft_max=1.0,
default=1.0,
precision=2,
); exec(conv("append_object_velocity_influence"))
priority = IntProperty(
)
priority: IntProperty(
name="Priority",
description="Priority that this fluid object is added to the simulation"
" during a frame. If multiple fluid/inflow objects are adding fluid"
@@ -68,38 +67,38 @@ class FlipFluidFluidProperties(bpy.types.PropertyGroup):
" objects",
min=-1000000, max=1000000,
default=0,
); exec(conv("priority"))
use_initial_velocity_target = BoolProperty(
)
use_initial_velocity_target: BoolProperty(
name ="Set towards target",
description="Set initial velocity towards a target object",
default=False,
options={'HIDDEN'}
); exec(conv("use_initial_velocity_target"))
fluid_velocity_mode = EnumProperty(
)
fluid_velocity_mode: EnumProperty(
name="Velocity Mode",
description="Set how the inital fluid velocity is calculated",
items=types.fluid_velocity_modes,
default='FLUID_VELOCITY_MANUAL',
options={'HIDDEN'},
); exec(conv("fluid_velocity_mode"))
initial_speed = bpy.props.FloatProperty(
)
initial_speed: bpy.props.FloatProperty(
name="Speed",
description="Initial speed of fluid towards target (m/s)",
default=0.0,
precision=3,
options={'HIDDEN'},
); exec(conv("initial_speed"))
fluid_axis_mode = EnumProperty(
)
fluid_axis_mode: EnumProperty(
name="Local Axis",
description="Set local axis direction of fluid",
items=types.local_axis_directions,
default='LOCAL_AXIS_POS_X',
); exec(conv("fluid_axis_mode"))
target_object = PointerProperty(
)
target_object: PointerProperty(
name="Target Object",
type=bpy.types.Object
); exec(conv("target_object"))
source_id = IntProperty(
)
source_id: IntProperty(
name="Source ID Attribute",
description="Assign this identifier value to the fluid generated by this object. After"
" baking, the source ID attribute values can be accessed in a Cycles Attribute Node"
@@ -109,34 +108,45 @@ class FlipFluidFluidProperties(bpy.types.PropertyGroup):
min=0, soft_max=16,
default=0,
options={'HIDDEN'},
); exec(conv("source_id"))
viscosity = FloatProperty(
)
viscosity: FloatProperty(
name="Viscosity Attribute",
description="Assign this viscosity value to the fluid generated by this object. After"
" baking, the viscosity attribute values can be accessed in a Cycles Attribute Node"
" with the name 'flip_viscosity' from the Fac output. This feature can be used to create"
" variable viscosity liquid effects. Enable this viscosity feature in the Domain FLIP"
" Fluid World panel",
" variable viscosity liquid effects. Enable this viscosity feature in the Domain"
" World panel",
min=0.0,
default=0.0,
); exec(conv("viscosity"))
lifetime = FloatProperty(
)
density: FloatProperty(
name="Density Attribute",
description="Assign this density value in g/cm^3 to the fluid generated by this object. After"
" baking, the density attribute values can be accessed in a Cycles Attribute Node"
" with the name 'flip_density' from the Fac output. This feature"
" can be used to create variable density liquids that float or sink. Enable this density feature"
" in the Domain World panel",
soft_min = 0.05, soft_max=20.0,
min=0.0001,
default=1.0,
)
lifetime: FloatProperty(
name="Lifetime Attribute",
description="Assign this starting lifetime value to the fluid generated by this object."
" This value is the amount of time remaining (in seconds) before the fluid is removed from the"
" simulation. After baking, the lifetime attribute values can be accessed in a Cycles Attribute Node"
" with the name 'flip_lifetime' from the Fac output. Enable this feature in the Domain FLIP"
" Fluid Surface panel",
" with the name 'flip_lifetime' from the Fac output. Enable this feature in the Domain "
" Surface or Particles panel",
min=0.0,
default=1000.0,
); exec(conv("lifetime"))
lifetime_variance = FloatProperty(
)
lifetime_variance: FloatProperty(
name="Lifetime Variance",
description="Add or subtract a random value in seconds to the starting lifetime within the range of this variance value",
min=0.0,
default=0.0,
); exec(conv("lifetime_variance"))
color = FloatVectorProperty(
)
color: FloatVectorProperty(
name="Color Attribute",
description="Assign this color to the fluid generated by this object. After"
" baking, the color attribute values can be accessed in a Cycles Attribute Node"
@@ -148,8 +158,8 @@ class FlipFluidFluidProperties(bpy.types.PropertyGroup):
size=3,
precision=3,
subtype='COLOR',
); exec(conv("color"))
export_animated_target = BoolProperty(
)
export_animated_target: BoolProperty(
name="Export Animated Target",
description="Export this object as an animated mesh. Exporting animated meshes are"
" slower, only use when necessary. This option is required for any animation that"
@@ -158,24 +168,24 @@ class FlipFluidFluidProperties(bpy.types.PropertyGroup):
" not needed for static objects",
default=False,
options={'HIDDEN'},
); exec(conv("export_animated_target"))
export_animated_mesh = BoolProperty(
)
export_animated_mesh: BoolProperty(
name="Export Animated Mesh",
description="Export this mesh as an animated one (slower, only use"
" if really necessary [e.g. armatures or parented objects],"
" animated pos/rot/scale F-curves do not require it",
default=False,
options={'HIDDEN'},
); exec(conv("export_animated_mesh"))
skip_reexport = BoolProperty(
)
skip_reexport: BoolProperty(
name="Skip Re-Export",
description="Skip re-exporting this mesh when starting or resuming"
" a bake. If this mesh has not been exported or is missing files,"
" the addon will automatically export the required files",
default=False,
options={'HIDDEN'},
); exec(conv("skip_reexport"))
force_reexport_on_next_bake = BoolProperty(
)
force_reexport_on_next_bake: BoolProperty(
name="Force Re-Export On Next Bake",
description="Override the 'Skip Re-Export' option and force this mesh to be"
" re-exported and updated on the next time a simulation start/resumes"
@@ -184,43 +194,43 @@ class FlipFluidFluidProperties(bpy.types.PropertyGroup):
" This option is only applicable if 'Skip Re-Export' is enabled",
default=False,
options={'HIDDEN'},
); exec(conv("force_reexport_on_next_bake"))
frame_offset_type = EnumProperty(
)
frame_offset_type: EnumProperty(
name="Trigger Type",
description="When to trigger fluid object",
items=types.frame_offset_types,
default='OFFSET_TYPE_FRAME',
options={'HIDDEN'},
); exec(conv("frame_offset_type"))
frame_offset = IntProperty(
)
frame_offset: IntProperty(
name="",
description="Frame offset from start of simulation to add fluid object"
" to domain",
min=0,
default=0,
options={'HIDDEN'},
); exec(conv("frame_offset"))
timeline_offset = bpy.props.IntProperty(
)
timeline_offset: bpy.props.IntProperty(
name="",
description="Timeline frame to add fluid object to domain",
min=0,
default=0,
options={'HIDDEN'},
); exec(conv("timeline_offset"))
property_registry = PointerProperty(
)
property_registry: PointerProperty(
name="Fluid Property Registry",
description="",
type=preset_properties.PresetRegistry,
); exec(conv("property_registry"))
)
disabled_in_viewport_tooltip = BoolProperty(
disabled_in_viewport_tooltip: BoolProperty(
name="Object Disabled in Viewport",
description="This fluid object is currently disabled in the viewport within the"
" outliner (Monitor Icon) and will not be included in the simulation. If you"
" want the object hidden in the viewport, but still have the object included in the"
" simulation, use the outliner Hide in Viewport option instead (Eye Icon)",
default=True,
); exec(conv("disabled_in_viewport_tooltip"))
)
def initialize(self):
@@ -244,6 +254,7 @@ class FlipFluidFluidProperties(bpy.types.PropertyGroup):
add("fluid.fluid_axis_mode", "")
add("fluid.source_id", "")
add("fluid.viscosity", "")
add("fluid.density", "")
add("inflow.lifetime", "")
add("inflow.lifetime_variance", "")
add("fluid.color", "")
@@ -32,29 +32,28 @@ from ..utils import version_compatibility_utils as vcu
class FlipFluidForceFieldProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
force_field_type = EnumProperty(
force_field_type: EnumProperty(
name="Type",
description="Type of force field",
items=types.force_field_types,
default='FORCE_FIELD_TYPE_POINT',
update=lambda self, context: self._update_force_field_type(context),
options={'HIDDEN'},
); exec(conv("force_field_type"))
is_enabled = BoolProperty(
)
is_enabled: BoolProperty(
name="Enabled",
description="Force field is active in the fluid simulation",
default=True,
); exec(conv("is_enabled"))
strength = FloatProperty(
)
strength: FloatProperty(
name="Strength",
description="Strength of the force field. A negative value pulls fluid in,"
" a positive value pushes fluid away",
default=-9.81,
precision=2,
); exec(conv("strength"))
falloff_power = FloatProperty(
)
falloff_power: FloatProperty(
name="Falloff Power",
description="How quickly force strength decreases with distance. If "
" r is the distance from the force object, the force strength changes"
@@ -64,18 +63,18 @@ class FlipFluidForceFieldProperties(bpy.types.PropertyGroup):
min=0.0,
soft_max=3.0, max=6.0,
precision=2,
); exec(conv("falloff_power"))
enable_min_distance = BoolProperty(
)
enable_min_distance: BoolProperty(
name="Enable Min Distance",
description="Use a minimum distance for the force field falloff",
default=False,
); exec(conv("enable_min_distance"))
enable_max_distance = BoolProperty(
)
enable_max_distance: BoolProperty(
name="Enable Max Distance",
description="Use a maximum distance for the force field to work",
default=False,
); exec(conv("enable_max_distance"))
min_max_distance = NewMinMaxFloatProperty(
)
min_max_distance: NewMinMaxFloatProperty(
name_min="Min Distance",
description_min="The distance from the force object at which the strength"
" begins to falloff",
@@ -90,8 +89,8 @@ class FlipFluidForceFieldProperties(bpy.types.PropertyGroup):
min_max=0,
default_max=0.0,
precision_max=3,
); exec(conv("min_max_distance"))
maximum_force_limit_factor = FloatProperty(
)
maximum_force_limit_factor: FloatProperty(
name="Max Force Limit Factor",
description="The maximum force in the field will be limited to the Strength"
" multiplied by this value",
@@ -99,8 +98,8 @@ class FlipFluidForceFieldProperties(bpy.types.PropertyGroup):
min=0.0,
soft_max=10.0,
precision=2,
); exec(conv("maximum_force_limit_factor"))
export_animated_mesh = bpy.props.BoolProperty(
)
export_animated_mesh: bpy.props.BoolProperty(
name="Export Animated Mesh",
description="Export this object as an animated mesh. Exporting animated meshes are"
" slower, only use when necessary. This option is required for any animation that"
@@ -109,16 +108,16 @@ class FlipFluidForceFieldProperties(bpy.types.PropertyGroup):
" not needed for static objects",
default=False,
options={'HIDDEN'},
); exec(conv("export_animated_mesh"))
skip_reexport = BoolProperty(
name="Skip re-export",
)
skip_reexport: BoolProperty(
name="Skip Re-export",
description="Skip re-exporting this mesh when starting or resuming"
" a bake. If this mesh has not been exported or is missing files,"
" the addon will automatically export the required files",
default=False,
options={'HIDDEN'},
); exec(conv("skip_reexport"))
force_reexport_on_next_bake = BoolProperty(
)
force_reexport_on_next_bake: BoolProperty(
name="Force Re-Export On Next Bake",
description="Override the 'Skip Re-Export' option and force this mesh to be"
" re-exported and updated on the next time a simulation start/resumes"
@@ -127,9 +126,9 @@ class FlipFluidForceFieldProperties(bpy.types.PropertyGroup):
" This option is only applicable if 'Skip Re-Export' is enabled",
default=False,
options={'HIDDEN'},
); exec(conv("force_reexport_on_next_bake"))
)
maximum_strength_tooltip = BoolProperty(
maximum_strength_tooltip: BoolProperty(
name="Maximum Force",
description="This value estimates the maximum possible force field strength"
" generated by this object. Force field strengths are inversely proportional"
@@ -137,7 +136,7 @@ class FlipFluidForceFieldProperties(bpy.types.PropertyGroup):
" Force Limit Factor to reduce the maximum force. For reference, a force strength"
" value of 9.81 is equal to the default strength of gravity",
default=True,
); exec(conv("maximum_strength_tooltip"))
)
#
@@ -145,94 +144,94 @@ class FlipFluidForceFieldProperties(bpy.types.PropertyGroup):
#
# Point Force Field
falloff_shape = EnumProperty(
falloff_shape: EnumProperty(
name="Falloff Shape",
description="(Placeholder, TODO) Specifies the shape of the force field. Only takes"
" effect if the Falloff Power is greater than 0",
items=types.force_field_falloff_shapes,
default='FORCE_FIELD_FALLOFF_SPHERE',
options={'HIDDEN'},
); exec(conv("falloff_shape"))
gravity_scale_point = FloatProperty(
)
gravity_scale_point: FloatProperty(
name="Gravity Scale",
description="Scale the force of gravity around this point by this value. A scale"
" of 0.0 is zero gravity, a scale of 1.0 is full gravity",
default=1.0,
soft_min=0.0, soft_max=1.0,
precision=2,
); exec(conv("gravity_scale_point"))
gravity_scale_width_point = FloatProperty(
)
gravity_scale_width_point: FloatProperty(
name="Gravity Scale Width",
description="The distance around this point that gravity scaling will take effect",
default=1.0,
min=0.0, soft_max=5.0,
precision=2,
); exec(conv("gravity_scale_width_point"))
)
# Surface Force Field
enable_frontfacing = BoolProperty(
enable_frontfacing: BoolProperty(
name="Front",
description="Enable force field on the front-facing side of the surface."
" This is the side where face normals point outwards",
default=True,
); exec(conv("enable_frontfacing"))
enable_backfacing = BoolProperty(
)
enable_backfacing: BoolProperty(
name="Back",
description="Enable force field on back-facing polygons."
" This is the side opposite of the face normal",
default=True,
); exec(conv("enable_backfacing"))
enable_edgefacing = BoolProperty(
)
enable_edgefacing: BoolProperty(
name="Edge",
description="Enable force field on planar edges."
" These are edges of the object that are not connected to any other polygons."
" Must have at lease one of Front or Back sides enabled",
default=True,
); exec(conv("enable_edgefacing"))
gravity_scale_surface = FloatProperty(
)
gravity_scale_surface: FloatProperty(
name="Gravity Scale",
description="Scale the force of gravity near the surface by this value. A scale"
" of 0.0 is zero gravity, a scale of 1.0 is full gravity",
default=1.0,
soft_min=0.0, soft_max=1.0,
precision=2,
); exec(conv("gravity_scale_surface"))
gravity_scale_width_surface = FloatProperty(
)
gravity_scale_width_surface: FloatProperty(
name="Gravity Scale Width",
description="The distance from the surface that gravity scaling will take effect",
default=1.0,
min=0.0, soft_max=5.0,
precision=2,
); exec(conv("gravity_scale_width_surface"))
)
# Volume Force Field
gravity_scale_volume = FloatProperty(
gravity_scale_volume: FloatProperty(
name="Gravity Scale",
description="Scale the force of gravity inside the volume by this value. A scale"
" of 0.0 is zero gravity, a scale of 1.0 is full gravity",
default=1.0,
soft_min=0.0, soft_max=1.0,
precision=2,
); exec(conv("gravity_scale_volume"))
gravity_scale_width_volume = FloatProperty(
)
gravity_scale_width_volume: FloatProperty(
name="Gravity Scale Width",
description="The distance from the outside of the volume's surface that gravity"
" scaling will take effect",
default=0.0,
min=0.0, soft_max=5.0,
precision=2,
); exec(conv("gravity_scale_width_volume"))
)
# Curve Force Field
flow_strength = FloatProperty(
flow_strength: FloatProperty(
name="Flow Strength",
description="Strength of the flow along the direction of the curve. The curve direction"
" is in the vertex order of the Blender Curve object. A negative value will reverse"
" the direction",
default=0.0,
precision=2,
); exec(conv("flow_strength"))
spin_strength = FloatProperty(
)
spin_strength: FloatProperty(
name="Spin Strength",
description="Strength of the the force that directs fluid to spin around the curve. A positive"
" strength uses the 'Right Hand Rule:' take your right hand and point your thumb in"
@@ -241,46 +240,46 @@ class FlipFluidForceFieldProperties(bpy.types.PropertyGroup):
" direction",
default=0.0,
precision=2,
); exec(conv("spin_strength"))
gravity_scale_curve = FloatProperty(
)
gravity_scale_curve: FloatProperty(
name="Gravity Scale",
description="Scale the force of gravity near the curve by this value. A scale"
" of 0.0 is zero gravity, a scale of 1.0 is full gravity",
default=1.0,
soft_min=0.0, soft_max=1.0,
precision=2,
); exec(conv("gravity_scale_curve"))
gravity_scale_width_curve = FloatProperty(
)
gravity_scale_width_curve: FloatProperty(
name="Gravity Scale Width",
description="The distance from the curve that gravity"
" scaling will take effect",
default=1.0,
min=0.0, soft_max=5.0,
precision=2,
); exec(conv("gravity_scale_width_curve"))
enable_endcaps = BoolProperty(
)
enable_endcaps: BoolProperty(
name="Enable End Caps",
description="Whether fluid is attracted towards the ends of the curve segment. Disable"
" to allow fluid to flow past the ends of the curve segment",
default=True,
); exec(conv("enable_endcaps"))
)
property_registry = PointerProperty(
property_registry: PointerProperty(
name="Outflow Property Registry",
description="",
type=preset_properties.PresetRegistry,
); exec(conv("property_registry"))
)
disabled_in_viewport_tooltip = BoolProperty(
disabled_in_viewport_tooltip: BoolProperty(
name="Object Disabled in Viewport",
description="This force field object is currently disabled in the viewport within the"
" outliner (Monitor Icon) and will not be included in the simulation. If you"
" want the object hidden in the viewport, but still have the object included in the"
" simulation, use the outliner Hide in Viewport option instead (Eye Icon)",
default=True,
); exec(conv("disabled_in_viewport_tooltip"))
)
@@ -547,21 +547,18 @@ class FlipFluidHelperPropertiesShadowCatcherState(bpy.types.PropertyGroup):
# Properties:
class FlipFluidHelperProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
option_path_supports_blend_relative = set()
if vcu.is_blender_45():
# required for relative path support in Blender 4.5+
# https://docs.blender.org/api/4.5/bpy_types_enum_items/property_flag_items.html#rna-enum-property-flag-items
option_path_supports_blend_relative = {'PATH_SUPPORTS_BLEND_RELATIVE'}
# required for relative path support in Blender 4.5+
# https://docs.blender.org/api/4.5/bpy_types_enum_items/property_flag_items.html#rna-enum-property-flag-items
option_path_supports_blend_relative = {'PATH_SUPPORTS_BLEND_RELATIVE'}
enable_auto_frame_load = BoolProperty(
enable_auto_frame_load: BoolProperty(
name="Auto-Load Baked Frames",
description="Automatically load frames as they finish baking",
default=False,
update=lambda self, context: self._update_enable_auto_frame_load_cmd(context),
); exec(conv("enable_auto_frame_load"))
enable_auto_frame_load_cmd = BoolProperty(
)
enable_auto_frame_load_cmd: BoolProperty(
name="Sync With CMD Bake",
description="Automatically load frames as they finish baking when running a command"
" line bake. Note: this feature may decrease Blender performance and responsiveness"
@@ -569,27 +566,27 @@ class FlipFluidHelperProperties(bpy.types.PropertyGroup):
" this option when a CMD bake is not running",
default=False,
update=lambda self, context: self._update_enable_auto_frame_load_cmd(context),
); exec(conv("enable_auto_frame_load_cmd"))
playback_frame_offset = IntProperty(
)
playback_frame_offset: IntProperty(
name="Frame Offset",
description="Frame offset for simulation playback. A positive offset will shift simulation playback forwards in the timeline while a negative offset will shift playback backwards in the timeline",
default=0,
options={'HIDDEN'},
); exec(conv("playback_frame_offset"))
)
cmd_bake_and_render = BoolProperty(
cmd_bake_and_render: BoolProperty(
name="Bake and Render",
description="Enable both baking and rendering in the command line process",
default=False,
); exec(conv("cmd_bake_and_render"))
cmd_bake_and_render_mode = EnumProperty(
)
cmd_bake_and_render_mode: EnumProperty(
name="CMD Bake and Render Mode",
description="How to bake and render the simulation",
items=types.cmd_bake_and_render_mode,
default='CMD_BAKE_AND_RENDER_MODE_SEQUENCE',
options={'HIDDEN'},
); exec(conv("cmd_bake_and_render_mode"))
cmd_bake_and_render_interleaved_instances = IntProperty(
)
cmd_bake_and_render_interleaved_instances: IntProperty(
name="Render Instances",
description="Maximum number of render instances to run simultaneously. This number is how many frames"
" are allowed to be rendered at the same time. More render instances maximizes system resource usage"
@@ -599,42 +596,42 @@ class FlipFluidHelperProperties(bpy.types.PropertyGroup):
min=1,
soft_max=8,
options={'HIDDEN'},
); exec(conv("cmd_bake_and_render_interleaved_instances"))
cmd_bake_and_render_interleaved_no_overwrite = BoolProperty(
)
cmd_bake_and_render_interleaved_no_overwrite: BoolProperty(
name="Continue render from last rendered frame",
description="Skip rendering frames that already exist in the render output directory. Useful for continuing a render from the last completed frame. If disabled, rendered frames will be overwritten",
default=True,
); exec(conv("cmd_bake_and_render_interleaved_no_overwrite"))
cmd_launch_render_animation_mode = EnumProperty(
)
cmd_launch_render_animation_mode: EnumProperty(
name="Animation Render Mode",
description="How to render the animation",
items=types.cmd_render_animation_mode,
default='CMD_RENDER_MODE_NORMAL',
options={'HIDDEN'},
); exec(conv("cmd_launch_render_animation_mode"))
cmd_launch_render_passes_animation_mode = EnumProperty(
)
cmd_launch_render_passes_animation_mode: EnumProperty(
name="Animation Render Mode",
description="How to render the compositing tools render passes animation",
items=types.cmd_render_passes_animation_mode,
default='CMD_RENDER_MODE_RENDER_PASSES',
options={'HIDDEN'},
); exec(conv("cmd_launch_render_passes_animation_mode"))
cmd_launch_render_normal_animation_no_overwrite = BoolProperty(
)
cmd_launch_render_normal_animation_no_overwrite: BoolProperty(
name="Skip rendered frames",
description="Skip rendering frames that already exist in the render output directory. Useful for continuing a render from the last completed frame. If disabled, rendered frames will be overwritten",
default=False,
); exec(conv("cmd_launch_render_normal_animation_no_overwrite"))
cmd_launch_render_animation_no_overwrite = BoolProperty(
)
cmd_launch_render_animation_no_overwrite: BoolProperty(
name="Skip rendered frames",
description="Skip rendering frames that already exist in the render output directory. Useful for continuing a render from the last completed frame. If disabled, rendered frames will be overwritten",
default=True,
); exec(conv("cmd_launch_render_animation_no_overwrite"))
cmd_launch_render_passes_animation_no_overwrite = BoolProperty(
)
cmd_launch_render_passes_animation_no_overwrite: BoolProperty(
name="Skip rendered frames",
description="Skip rendering compositing pass frames that already exist in the render output directory. Useful for continuing a render from the last completed compositing pass frame. If disabled, rendered frames will be overwritten",
default=True,
); exec(conv("cmd_launch_render_passes_animation_no_overwrite"))
cmd_launch_render_animation_instances = IntProperty(
)
cmd_launch_render_animation_instances: IntProperty(
name="Render Instances",
description="Maximum number of render instances to run simultaneously. This number is how many frames"
" are allowed to be rendered at the same time. More render instances maximizes system resource usage"
@@ -643,8 +640,8 @@ class FlipFluidHelperProperties(bpy.types.PropertyGroup):
min=1,
soft_max=8,
options={'HIDDEN'},
); exec(conv("cmd_launch_render_animation_instances"))
cmd_launch_render_passes_animation_instances = IntProperty(
)
cmd_launch_render_passes_animation_instances: IntProperty(
name="Render Instances",
description="Maximum number of render instances to run simultaneously. This number is how many compositing pass frames"
" are allowed to be rendered at the same time. More render instances maximizes system resource usage"
@@ -653,29 +650,29 @@ class FlipFluidHelperProperties(bpy.types.PropertyGroup):
min=1,
soft_max=8,
options={'HIDDEN'},
); exec(conv("cmd_launch_render_passes_animation_instances"))
cmd_open_image_after_render = BoolProperty(
)
cmd_open_image_after_render: BoolProperty(
name="Open Image After Render",
description="After the command line render process is finished, open the image in your default OS image program",
default=True,
); exec(conv("cmd_open_image_after_render"))
cmd_close_window_after_render = BoolProperty(
)
cmd_close_window_after_render: BoolProperty(
name="Close CMD Window After Render",
description="After the command line render process is finished, open the image in your default OS image program",
default=False,
); exec(conv("cmd_close_window_after_render"))
)
### NEW RENDER PASSES ###
# Disabled by default for the release of FLIP Fluids 1.8.0
display_compositing_tools_in_ui = BoolProperty(default=False); exec(conv("display_compositing_tools_in_ui"))
display_compositing_tools_in_ui: BoolProperty(default=False)
render_passes = BoolProperty(
render_passes: BoolProperty(
name="Activate Passes Rendering",
description="Activate rendering of selected passes",
default=False
); exec(conv("render_passes"))
)
render_passes_objectlist: bpy.props.CollectionProperty(type=FlipFluidHelperPropertiesRenderPassesObjectslist)
render_passes_fg_elementslist: bpy.props.CollectionProperty(type=FlipFluidHelperPropertiesRenderPassesObjectslist)
@@ -999,68 +996,80 @@ class FlipFluidHelperProperties(bpy.types.PropertyGroup):
### END OF PASSES ###
alembic_export_surface = BoolProperty(
alembic_export_engine: EnumProperty(
name="Alembic Export Engine",
description="Select the Alembic export engine",
items=types.alembic_export_engines,
default='ALEMBIC_EXPORT_ENGINE_BLENDER',
options={'HIDDEN'},
)
alembic_export_surface: BoolProperty(
name="Surface",
description="Include fluid surface mesh in the Alembic export",
default=True,
); exec(conv("alembic_export_surface"))
alembic_export_fluid_particles = BoolProperty(
)
alembic_export_surface_preview: BoolProperty(
name="Preview",
description="Include fluid surface preview mesh in the Alembic export",
default=False,
)
alembic_export_fluid_particles: BoolProperty(
name="Fluid Particles",
description="Include fluid particles in the Alembic export",
default=False,
); exec(conv("alembic_export_fluid_particles"))
alembic_export_foam = BoolProperty(
)
alembic_export_foam: BoolProperty(
name="Foam",
description="Include whitewater foam mesh in the Alembic export if applicable. This mesh will be exported as a vertex-only mesh",
default=True,
); exec(conv("alembic_export_foam"))
alembic_export_bubble = BoolProperty(
)
alembic_export_bubble: BoolProperty(
name="Bubble",
description="Include whitewater bubble mesh in the Alembic export if applicable. This mesh will be exported as a vertex-only mesh",
default=True,
); exec(conv("alembic_export_bubble"))
alembic_export_spray = BoolProperty(
)
alembic_export_spray: BoolProperty(
name="Spray",
description="Include whitewater spray mesh in the Alembic export if applicable. This mesh will be exported as a vertex-only mesh",
default=True,
); exec(conv("alembic_export_spray"))
alembic_export_dust = BoolProperty(
)
alembic_export_dust: BoolProperty(
name="Dust",
description="Include whitewater dust mesh in the Alembic export if applicable. This mesh will be exported as a vertex-only mesh",
default=True,
); exec(conv("alembic_export_dust"))
alembic_export_velocity = BoolProperty(
)
alembic_export_velocity: BoolProperty(
name="Export Velocity",
description="Include velocity data in the Alembic export. This data will be available"
" under the 'velocity' point attribute of the Alembic export and can be used for motion"
" blur rendering. Velocity attributes for the surface, fluid particles, and/or whitewater are required to"
" be baked before export",
default=False,
); exec(conv("alembic_export_velocity"))
alembic_export_color = BoolProperty(
)
alembic_export_color: BoolProperty(
name="Export Color",
description="Include color attribute data in the Alembic export. This data will be available"
" under the 'color' face-corner attribute of the Alembic export and can be used for material shading."
" This attribute is only supported for the Surface mesh."
" Color attributes for the surface are required to be baked before export",
default=False,
); exec(conv("alembic_export_color"))
alembic_global_scale = FloatProperty(
)
alembic_global_scale: FloatProperty(
name="Scale",
description="Scale value by which to enlarge or shrink the simulation meshes with respect to the world's origin",
min=0.0001,
max=1000.0,
default=1.0,
precision=3,
); exec(conv("alembic_global_scale"))
alembic_frame_range_mode = EnumProperty(
)
alembic_frame_range_mode: EnumProperty(
name="Frame Range Mode",
description="Frame range to use for Alembic Export",
items=types.frame_range_modes,
default='FRAME_RANGE_TIMELINE',
options={'HIDDEN'},
); exec(conv("alembic_frame_range_mode"))
alembic_frame_range_custom = NewMinMaxIntProperty(
)
alembic_frame_range_custom: NewMinMaxIntProperty(
name_min="Start Frame",
description_min="First frame of the Alembic export",
min_min=0,
@@ -1072,8 +1081,8 @@ class FlipFluidHelperProperties(bpy.types.PropertyGroup):
min_max=0,
default_max=250,
options_max={'HIDDEN'},
); exec(conv("alembic_frame_range_custom"))
alembic_output_filepath = StringProperty(
)
alembic_output_filepath: StringProperty(
name="",
description="Alembic export will be saved to this filepath. Remember to save the Blend file before"
" starting the Alembic export",
@@ -1081,68 +1090,68 @@ class FlipFluidHelperProperties(bpy.types.PropertyGroup):
subtype='FILE_PATH',
options=option_path_supports_blend_relative,
update=lambda self, context: self._update_alembic_output_filepath(context),
); exec(conv("alembic_output_filepath"))
is_alembic_output_filepath_set = BoolProperty(default=False); exec(conv("is_alembic_output_filepath_set"))
)
is_alembic_output_filepath_set: BoolProperty(default=False)
unsaved_blend_file_tooltip = BoolProperty(
unsaved_blend_file_tooltip: BoolProperty(
name="Unsaved Blend File Tooltip",
description="This is currently an unsaved .blend file. We recommend saving your file before baking a"
" simulation so you do not accidentally lose your simulation progress or settings",
default=True,
); exec(conv("unsaved_blend_file_tooltip"))
)
turbo_tools_render_tooltip = BoolProperty(
turbo_tools_render_tooltip: BoolProperty(
name="Turbo Tools command line rendering support",
description="An installation of the Turbo Tools addon has been detected. Use these operators to launch"
" a Turbo Tools render process or copy the render command. Refer to the Turbo Tools documentation for more info"
" on command line rendering",
default=True,
); exec(conv("turbo_tools_render_tooltip"))
)
flip_fluids_remesh_skip_hide_render_objects = BoolProperty(
flip_fluids_remesh_skip_hide_render_objects: BoolProperty(
name="Skip Hidden Render Objects",
description="Skip remeshing objects in the collection that are hidden from render (outliner camera icon)",
default=False,
); exec(conv("flip_fluids_remesh_skip_hide_render_objects"))
flip_fluids_remesh_apply_object_modifiers = BoolProperty(
)
flip_fluids_remesh_apply_object_modifiers: BoolProperty(
name="Apply Object Modifiers",
description="Automatically apply modifiers to objects in collection. If disabled, objects with modifiers will"
" need to have modifiers applied manually or excluded from the viewport (disable outliner monitor icon)"
" before proceeding with the remesh process. Modifiers may not be applied in the intended order and objects"
" with complex modifier dependencies may need to be applied manually for accuracy",
default=True,
); exec(conv("flip_fluids_remesh_apply_object_modifiers"))
flip_fluids_remesh_convert_objects_to_mesh = BoolProperty(
)
flip_fluids_remesh_convert_objects_to_mesh: BoolProperty(
name="Convert Objects to Mesh",
description="Automatically convert non-mesh type objects in the collection to a mesh type if applicable. If an object cannot"
" be converted to a mesh (empties, armatures, etc), the object will be skipped from the remeshing process."
" If disabled, non-mesh type objects will need to be manually converted to a mesh or excluded from the viewport"
" (disable outliner monitor icon) before proceeding with the remesh process",
default=True,
); exec(conv("flip_fluids_remesh_convert_objects_to_mesh"))
update_object_speed_data_on_frame_change = BoolProperty(
)
update_object_speed_data_on_frame_change: BoolProperty(
name="Update on frame change",
description="Update the object speed measurement for the active object after changing a frame. Not recommended"
" to leave this option enabled when not in use as this could slow down Blender when measuring complex or high poly geometry",
default=False,
); exec(conv("update_object_speed_data_on_frame_change"))
measure_object_speed_units_mode = EnumProperty(
)
measure_object_speed_units_mode: EnumProperty(
name="Measurement Units",
description="Display speed in metric or imperial units",
items=types.measurement_units_mode,
default='MEASUREMENT_UNITS_MODE_METRIC',
options={'HIDDEN'},
); exec(conv("measure_object_speed_units_mode"))
)
disable_addon_in_blend_file = BoolProperty(
disable_addon_in_blend_file: BoolProperty(
name="Disable Addon in Blend File",
description="",
default=False,
); exec(conv("disable_addon_in_blend_file"))
)
is_auto_frame_load_cmd_operator_running = BoolProperty(default=False); exec(conv("is_auto_frame_load_cmd_operator_running"))
is_auto_frame_load_cmd_operator_running: BoolProperty(default=False)
export_animated_mesh_parent_tooltip = BoolProperty(
export_animated_mesh_parent_tooltip: BoolProperty(
name="Hint: Export Animated Mesh",
description="A parented relation has been detected on this object. If this object"
" is moving, enabling the 'Export Animated Mesh' option is required to evaluate"
@@ -1150,41 +1159,18 @@ class FlipFluidHelperProperties(bpy.types.PropertyGroup):
" animation that is more complex than keyframed loc/rot/scale such as parented objects."
" If the object is static, keep this option disabled",
default=True,
); exec(conv("export_animated_mesh_parent_tooltip"))
)
# Used in Helper Operators > FlipFluidMeasureObjectSpeed operator
is_translation_data_available = BoolProperty(default=False); exec(conv("is_translation_data_available"))
min_vertex_translation = FloatProperty(default=0.0); exec(conv("min_vertex_translation"))
max_vertex_translation = FloatProperty(default=0.0); exec(conv("max_vertex_translation"))
avg_vertex_translation = FloatProperty(default=0.0); exec(conv("avg_vertex_translation"))
center_translation = FloatProperty(default=0.0); exec(conv("center_translation"))
translation_data_object_name = StringProperty(default="Name Not Available"); exec(conv("translation_data_object_name"))
translation_data_object_vertices = IntProperty(default=-1); exec(conv("translation_data_object_vertices"))
translation_data_object_frame = IntProperty(default=-1); exec(conv("translation_data_object_frame"))
translation_data_object_compute_time = IntProperty(default=-1); exec(conv("translation_data_object_compute_time"))
prepare_geometry_tools_expanded = BoolProperty(default=False); exec(conv("prepare_geometry_tools_expanded"))
bake_simulation_expanded = BoolProperty(default=True); exec(conv("bake_simulation_expanded"))
add_remove_objects_expanded = BoolProperty(default=False); exec(conv("add_remove_objects_expanded"))
outliner_organization_expanded = BoolProperty(default=False); exec(conv("outliner_organization_expanded"))
quick_select_expanded = BoolProperty(default=False); exec(conv("quick_select_expanded"))
command_line_tools_expanded = BoolProperty(default=True); exec(conv("command_line_tools_expanded"))
command_line_bake_expanded = BoolProperty(default=False); exec(conv("command_line_bake_expanded"))
command_line_render_passes_expanded = BoolProperty(default=False); exec(conv("command_line_render_passes_expanded"))
command_line_render_expanded = BoolProperty(default=False); exec(conv("command_line_render_expanded"))
command_line_render_frame_expanded = BoolProperty(default=False); exec(conv("command_line_render_frame_expanded"))
command_line_render_turbo_tools_expanded = BoolProperty(default=False); exec(conv("command_line_render_turbo_tools_expanded"))
command_line_alembic_export_expanded = BoolProperty(default=False); exec(conv("command_line_alembic_export_expanded"))
geometry_node_tools_expanded = BoolProperty(default=False); exec(conv("geometry_node_tools_expanded"))
object_speed_measurement_tools_expanded = BoolProperty(default=False); exec(conv("object_speed_measurement_tools_expanded"))
beginner_tools_expanded = BoolProperty(default=False); exec(conv("beginner_tools_expanded"))
disable_addon_expanded = BoolProperty(default=False); exec(conv("disable_addon_expanded"))
quick_viewport_display_expanded = BoolProperty(default=True); exec(conv("quick_viewport_display_expanded"))
simulation_playback_expanded = BoolProperty(default=False); exec(conv("simulation_playback_expanded"))
render_tools_expanded = BoolProperty(default=False); exec(conv("render_tools_expanded"))
is_translation_data_available: BoolProperty(default=False)
min_vertex_translation: FloatProperty(default=0.0)
max_vertex_translation: FloatProperty(default=0.0)
avg_vertex_translation: FloatProperty(default=0.0)
center_translation: FloatProperty(default=0.0)
translation_data_object_name: StringProperty(default="Name Not Available")
translation_data_object_vertices: IntProperty(default=-1)
translation_data_object_frame: IntProperty(default=-1)
translation_data_object_compute_time: IntProperty(default=-1)
@classmethod
@@ -31,14 +31,13 @@ from ..utils import version_compatibility_utils as vcu
class FlipFluidInflowProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
is_enabled = BoolProperty(
is_enabled: BoolProperty(
name="Enabled",
description="Inflow emits fluid into the domain. Tip: keyframe this option on/off to start and stop inflow emission",
default=True,
); exec(conv("is_enabled"))
substep_emissions = IntProperty(
)
substep_emissions: IntProperty(
name="Substep Emissions",
description="Number of times fluid is emitted from the inflow"
" per simulation substep. Increase to reduce stuttering"
@@ -47,22 +46,22 @@ class FlipFluidInflowProperties(bpy.types.PropertyGroup):
" substep of a frame",
min=0, soft_max=8,
default=1,
); exec(conv("substep_emissions"))
inflow_velocity = FloatVectorProperty(
)
inflow_velocity: FloatVectorProperty(
name="Inflow Velocity",
description="Initial velocity of fluid (m/s)",
default=(0.0, 0.0, 0.0),
subtype='VELOCITY',
precision=3,
size=3,
); exec(conv("inflow_velocity"))
append_object_velocity = BoolProperty(
)
append_object_velocity: BoolProperty(
name="Add Object Velocity to Infow",
description="Add the velocity of the object to the inflow fluid"
" velocity",
default=False,
); exec(conv("append_object_velocity"))
append_object_velocity_influence = FloatProperty(
)
append_object_velocity_influence: FloatProperty(
name="Influence",
description="Amount of velocity that is added to the inflow fluid."
" A value of 1.0 is normal, less than 1.0 will dampen the"
@@ -72,8 +71,8 @@ class FlipFluidInflowProperties(bpy.types.PropertyGroup):
soft_min=0.0, soft_max=1.0,
default=1.0,
precision=2,
); exec(conv("append_object_velocity_influence"))
priority = IntProperty(
)
priority: IntProperty(
name="Priority",
description="Priority that this fluid object is added to the simulation"
" during a frame. If multiple fluid/inflow objects are adding fluid"
@@ -83,31 +82,31 @@ class FlipFluidInflowProperties(bpy.types.PropertyGroup):
" objects",
min=-1000000, max=1000000,
default=0,
); exec(conv("priority"))
inflow_velocity_mode = EnumProperty(
)
inflow_velocity_mode: EnumProperty(
name="Velocity Mode",
description="Set how the inflow fluid velocity is calculated",
items=types.inflow_velocity_modes,
default='INFLOW_VELOCITY_MANUAL',
options={'HIDDEN'},
); exec(conv("inflow_velocity_mode"))
inflow_speed = FloatProperty(
)
inflow_speed: FloatProperty(
name="Speed",
description="Initial speed of fluid towards target (m/s)",
default=0.0,
precision=3,
); exec(conv("inflow_speed"))
inflow_axis_mode = EnumProperty(
)
inflow_axis_mode: EnumProperty(
name="Local Axis",
description="Set local axis direction of fluid",
items=types.local_axis_directions,
default='LOCAL_AXIS_POS_X',
); exec(conv("inflow_axis_mode"))
target_object = PointerProperty(
)
target_object: PointerProperty(
name="Target Object",
type=bpy.types.Object
); exec(conv("target_object"))
export_animated_target = BoolProperty(
)
export_animated_target: BoolProperty(
name="Export Animated Target",
description="Export this object as an animated mesh. Exporting animated meshes are"
" slower, only use when necessary. This option is required for any animation that"
@@ -116,8 +115,8 @@ class FlipFluidInflowProperties(bpy.types.PropertyGroup):
" not needed for static objects",
default=False,
options={'HIDDEN'},
); exec(conv("export_animated_target"))
constrain_fluid_velocity = BoolProperty(
)
constrain_fluid_velocity: BoolProperty(
name="Constrain Fluid Velocity",
description="Force fluid inside of the inflow to match the inflow" +
" emission velocity. If enabled, the inflow will continue to" +
@@ -125,8 +124,8 @@ class FlipFluidInflowProperties(bpy.types.PropertyGroup):
" values will have the effect of slowing down fluid emission",
default=False,
options={'HIDDEN'},
); exec(conv("constrain_fluid_velocity"))
source_id = IntProperty(
)
source_id: IntProperty(
name="Source ID Attribute",
description="Assign this identifier value to the fluid generated by this inflow. After"
" baking, the source ID attribute values can be accessed in a Cycles Attribute Node"
@@ -136,8 +135,8 @@ class FlipFluidInflowProperties(bpy.types.PropertyGroup):
min=0, soft_max=16,
default=0,
options={'HIDDEN'},
); exec(conv("source_id"))
viscosity = FloatProperty(
)
viscosity: FloatProperty(
name="Viscosity Attribute",
description="Assign this viscosity value to the fluid generated by this object. After"
" baking, the viscosity attribute values can be accessed in a Cycles Attribute Node"
@@ -146,8 +145,19 @@ class FlipFluidInflowProperties(bpy.types.PropertyGroup):
" Fluid World panel",
min=0.0,
default=0.0,
); exec(conv("viscosity"))
lifetime = FloatProperty(
)
density: FloatProperty(
name="Density Attribute",
description="Assign this density value in g/cm^3 to the fluid generated by this object. After"
" baking, the density attribute values can be accessed in a Cycles Attribute Node"
" with the name 'flip_density' from the Fac output. This feature"
" can be used to create variable density liquids that float or sink. Enable this density feature"
" in the Domain World panel",
soft_min = 0.05, soft_max=20.0,
min=0.0001,
default=1.0,
)
lifetime: FloatProperty(
name="Lifetime Attribute",
description="Assign this starting lifetime value to the fluid generated by this object."
" This value is the amount of time remaining (in seconds) before the fluid is removed from the"
@@ -156,14 +166,14 @@ class FlipFluidInflowProperties(bpy.types.PropertyGroup):
" Fluid Surface panel",
min=0.0,
default=1000.0,
); exec(conv("lifetime"))
lifetime_variance = FloatProperty(
)
lifetime_variance: FloatProperty(
name="Lifetime Variance",
description="Add or subtract a random value in seconds to the starting lifetime within the range of this variance value",
min=0.0,
default=0.0,
); exec(conv("lifetime_variance"))
color = FloatVectorProperty(
)
color: FloatVectorProperty(
name="Color Attribute",
description="Assign this color to the fluid generated by this object. After"
" baking, the color attribute values can be accessed in a Cycles Attribute Node"
@@ -175,24 +185,24 @@ class FlipFluidInflowProperties(bpy.types.PropertyGroup):
size=3,
precision=3,
subtype='COLOR',
); exec(conv("color"))
export_animated_mesh = BoolProperty(
)
export_animated_mesh: BoolProperty(
name="Export Animated Mesh",
description="Export this mesh as an animated one (slower, only use"
" if really necessary [e.g. armatures or parented objects],"
" animated pos/rot/scale F-curves do not require it",
default=False,
options={'HIDDEN'},
); exec(conv("export_animated_mesh"))
skip_reexport = BoolProperty(
name="Skip re-export",
)
skip_reexport: BoolProperty(
name="Skip Re-export",
description="Skip re-exporting this mesh when starting or resuming"
" a bake. If this mesh has not been exported or is missing files,"
" the addon will automatically export the required files",
default=False,
options={'HIDDEN'},
); exec(conv("skip_reexport"))
force_reexport_on_next_bake = BoolProperty(
)
force_reexport_on_next_bake: BoolProperty(
name="Force Re-Export On Next Bake",
description="Override the 'Skip Re-Export' option and force this mesh to be"
" re-exported and updated on the next time a simulation start/resumes"
@@ -201,22 +211,22 @@ class FlipFluidInflowProperties(bpy.types.PropertyGroup):
" This option is only applicable if 'Skip Re-Export' is enabled",
default=False,
options={'HIDDEN'},
); exec(conv("force_reexport_on_next_bake"))
property_registry = PointerProperty(
)
property_registry: PointerProperty(
name="Inflow Property Registry",
description="",
type=preset_properties.PresetRegistry,
); exec(conv("property_registry"))
)
disabled_in_viewport_tooltip = BoolProperty(
disabled_in_viewport_tooltip: BoolProperty(
name="Object Disabled in Viewport",
description="This inflow object is currently disabled in the viewport within the"
" outliner (Monitor Icon) and will not be included in the simulation. If you"
" want the object hidden in the viewport, but still have the object included in the"
" simulation, use the outliner Hide in Viewport option instead (Eye Icon)",
default=True,
); exec(conv("disabled_in_viewport_tooltip"))
)
@@ -244,6 +254,7 @@ class FlipFluidInflowProperties(bpy.types.PropertyGroup):
add("inflow.inflow_axis_mode", "")
add("inflow.source_id", "")
add("inflow.viscosity", "")
add("inflow.density", "")
add("inflow.lifetime", "")
add("inflow.lifetime_variance", "")
add("inflow.color", "")
@@ -26,20 +26,19 @@ from ..utils import version_compatibility_utils as vcu
class FlipFluidMaterialLibraryProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
# Material Library Data
is_library_material = BoolProperty(default=False); exec(conv("is_library_material"))
library_name = StringProperty(default=""); exec(conv("library_name"))
imported_name = StringProperty(default=""); exec(conv("imported_name"))
data_block_id = StringProperty(default="-1"); exec(conv("data_block_id"))
is_library_material: BoolProperty(default=False)
library_name: StringProperty(default="")
imported_name: StringProperty(default="")
data_block_id: StringProperty(default="-1")
# Preset Library Data
is_preset_material = BoolProperty(default=False); exec(conv("is_preset_material"))
preset_identifier = StringProperty(default=""); exec(conv("preset_identifier"))
preset_blend_identifier = StringProperty(default=""); exec(conv("preset_blend_identifier"))
is_fake_user_set_by_addon = BoolProperty(default=False); exec(conv("is_fake_user_set_by_addon"))
skip_preset_unload = BoolProperty(default=False); exec(conv("skip_preset_unload"))
is_preset_material: BoolProperty(default=False)
preset_identifier: StringProperty(default="")
preset_blend_identifier: StringProperty(default="")
is_fake_user_set_by_addon: BoolProperty(default=False)
skip_preset_unload: BoolProperty(default=False)
@classmethod
@@ -54,47 +54,45 @@ from ..utils import api_workaround_utils
class ObjectViewSettings(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
hide_render = BoolProperty(default=False); exec(conv("hide_render"))
show_name = BoolProperty(default=False); exec(conv("show_name"))
draw_type = StringProperty(default=""); exec(conv("draw_type"))
layers = BoolVectorProperty(size=20); exec(conv("layers"))
hide_render: BoolProperty(default=False)
show_name: BoolProperty(default=False)
draw_type: StringProperty(default="")
layers: BoolVectorProperty(size=20)
class FlipFluidObjectProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
domain = PointerProperty(
domain: PointerProperty(
name="Flip Fluid Domain Properties",
description="",
type=domain_properties.FlipFluidDomainProperties,
); exec(conv("domain"))
fluid = PointerProperty(
)
fluid: PointerProperty(
name="Flip Fluid Fluid Properties",
description="",
type=fluid_properties.FlipFluidFluidProperties,
); exec(conv("fluid"))
obstacle = PointerProperty(
)
obstacle: PointerProperty(
name="Flip Fluid Obstacle Properties",
description="",
type=obstacle_properties.FlipFluidObstacleProperties,
); exec(conv("obstacle"))
inflow = PointerProperty(
)
inflow: PointerProperty(
name="Flip Fluid Inflow Properties",
description="",
type=inflow_properties.FlipFluidInflowProperties,
); exec(conv("inflow"))
outflow = PointerProperty(
)
outflow: PointerProperty(
name="Flip Fluid Outflow Properties",
description="",
type=outflow_properties.FlipFluidOutflowProperties,
); exec(conv("outflow"))
force_field = PointerProperty(
)
force_field: PointerProperty(
name="Flip Fluid Force Field Properties",
description="",
type=force_field_properties.FlipFluidForceFieldProperties,
); exec(conv("force_field"))
object_type = EnumProperty(
)
object_type: EnumProperty(
name="Type",
description="Type of participation in the FLIP fluid simulation",
items=types.object_types,
@@ -102,16 +100,16 @@ class FlipFluidObjectProperties(bpy.types.PropertyGroup):
set=lambda self, value: self._set_object_type(value),
update=lambda self, context: self._update_object_type(context),
options={'HIDDEN'},
); exec(conv("object_type"))
saved_view_settings = PointerProperty(
)
saved_view_settings: PointerProperty(
name="Saved View Settings",
description="",
type=ObjectViewSettings,
); exec(conv("saved_view_settings"))
)
is_active = BoolProperty(default=False); exec(conv("is_active"))
is_view_settings_saved = BoolProperty(default=False); exec(conv("is_view_settings_saved"))
last_hide_render_state = BoolProperty(default=False); exec(conv("last_hide_render_state"))
is_active: BoolProperty(default=False)
is_view_settings_saved: BoolProperty(default=False)
last_hide_render_state: BoolProperty(default=False)
@classmethod
@@ -198,20 +196,12 @@ class FlipFluidObjectProperties(bpy.types.PropertyGroup):
def _toggle_cycles_ray_visibility(self, obj, is_enabled):
# Cycles may not be enabled in the user's preferences
try:
if vcu.is_blender_30():
obj.visible_camera = is_enabled
obj.visible_diffuse = is_enabled
obj.visible_glossy = is_enabled
obj.visible_transmission = is_enabled
obj.visible_volume_scatter = is_enabled
obj.visible_shadow = is_enabled
else:
obj.cycles_visibility.camera = is_enabled
obj.cycles_visibility.transmission = is_enabled
obj.cycles_visibility.diffuse = is_enabled
obj.cycles_visibility.scatter = is_enabled
obj.cycles_visibility.glossy = is_enabled
obj.cycles_visibility.shadow = is_enabled
obj.visible_camera = is_enabled
obj.visible_diffuse = is_enabled
obj.visible_glossy = is_enabled
obj.visible_transmission = is_enabled
obj.visible_volume_scatter = is_enabled
obj.visible_shadow = is_enabled
except:
pass
@@ -220,8 +210,6 @@ class FlipFluidObjectProperties(bpy.types.PropertyGroup):
# Should only be executed upon creation of a domain object in Blender 2.8x.
# Locking the Blender interface is necessary to prevent crashes in Blender >= v2.81
# and helps prevent crashes in Blender 2.80
if not vcu.is_blender_28():
return
bpy.context.scene.render.use_lock_interface = True
@@ -283,8 +271,6 @@ class FlipFluidObjectProperties(bpy.types.PropertyGroup):
def _update_object_type(self, context):
obj = vcu.get_active_object(context)
primary_layer = 0
object_layer = 14
if self.object_type == 'TYPE_DOMAIN':
if bpy.context.scene.flip_fluid.get_num_domain_objects() > 1:
@@ -346,6 +332,18 @@ class FlipFluidObjectProperties(bpy.types.PropertyGroup):
self.object_type = 'TYPE_NONE'
return
if obj.type == 'POINTCLOUD' and self.object_type != 'TYPE_NONE':
errmsg = "Point Cloud type objects are not supported."
errdesc = "Point Cloud objects are not supported as a FLIP Fluid object type."
bpy.ops.flip_fluid_operators.display_error(
'INVOKE_DEFAULT',
error_message=errmsg,
error_description=errdesc,
popup_width=600
)
self.object_type = 'TYPE_NONE'
return
if obj.type == 'META' and self.object_type != 'TYPE_NONE':
errmsg = "Metaball type objects are not supported."
errdesc = "Metaball type objects are not supported. Please convert to a mesh object before setting as FLIP Fluid object."
@@ -459,44 +457,31 @@ class FlipFluidObjectProperties(bpy.types.PropertyGroup):
obj.hide_render = True
vcu.set_object_display_type(obj, 'BOUNDS')
obj.show_name = True
self._set_object_layer(obj, object_layer)
self._set_scene_layer(context.scene, object_layer)
elif self.object_type == 'TYPE_FLUID':
obj.hide_render = True
vcu.set_object_display_type(obj, 'WIRE')
obj.show_name = True
self._set_object_layer(obj, object_layer)
self._set_scene_layer(context.scene, object_layer)
elif self.object_type == 'TYPE_OBSTACLE':
obj.hide_render = False
vcu.set_object_display_type(obj, 'TEXTURED')
obj.show_name = True
self._set_object_layers(obj, [primary_layer, object_layer])
self._set_scene_layer(context.scene, primary_layer)
self._set_scene_layer(context.scene, object_layer)
elif self.object_type == 'TYPE_INFLOW':
obj.hide_render = True
vcu.set_object_display_type(obj, 'WIRE')
obj.show_name = True
self._set_object_layer(obj, object_layer)
self._set_scene_layer(context.scene, object_layer)
elif self.object_type == 'TYPE_OUTFLOW':
obj.hide_render = True
vcu.set_object_display_type(obj, 'WIRE')
obj.show_name = True
self._set_object_layer(obj, object_layer)
self._set_scene_layer(context.scene, object_layer)
elif self.object_type == 'TYPE_FORCE_FIELD':
obj.hide_render = True
vcu.set_object_display_type(obj, 'WIRE')
obj.show_name = True
self._set_object_layer(obj, object_layer)
self._set_scene_layer(context.scene, object_layer)
if obj.type == 'CURVE':
ff_props = obj.flip_fluid.get_property_group()
@@ -510,12 +495,6 @@ class FlipFluidObjectProperties(bpy.types.PropertyGroup):
self.saved_view_settings.hide_render = obj.hide_render
self.saved_view_settings.show_name = obj.show_name
self.saved_view_settings.draw_type = vcu.get_object_display_type(obj)
# Layers do not seem to be in Blender 2.80
if not vcu.is_blender_28():
for i in range(20):
self.saved_view_settings.layers[i] = obj.layers[i]
self.is_view_settings_saved = True
@@ -526,45 +505,9 @@ class FlipFluidObjectProperties(bpy.types.PropertyGroup):
obj.hide_render = self.saved_view_settings.hide_render
obj.show_name = self.saved_view_settings.show_name
vcu.set_object_display_type(obj, self.saved_view_settings.draw_type)
# Layers do not seem to be in Blender 2.80
if not vcu.is_blender_28():
for i in range(20):
obj.layers[i] = True
for i in range(20):
obj.layers[i] = self.saved_view_settings.layers[i]
self.is_view_settings_saved = False
def _set_object_layer(self, obj, layeridx):
if vcu.is_blender_28():
# Layers do not seem to be in Blender 2.80
return
obj.layers[layeridx] = True
for i in range(20):
obj.layers[i] = (i == layeridx)
def _set_object_layers(self, obj, layers):
if vcu.is_blender_28():
# Layers do not seem to be in Blender 2.80
return
obj.layers[layers[0]] = True
for i in range(20):
obj.layers[i] = (i in layers)
def _set_scene_layer(self, scene, layeridx):
if vcu.is_blender_28():
# Layers do not seem to be in Blender 2.80
return
scene.layers[layeridx] = True
def scene_update_post(scene):
domain_properties.scene_update_post(scene)
@@ -26,14 +26,13 @@ from ..utils import version_compatibility_utils as vcu
class FlipFluidObstacleProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
is_enabled = BoolProperty(
is_enabled: BoolProperty(
name="Enabled",
description="Obstacle is present in the fluid simulation",
default=True,
); exec(conv("is_enabled"))
is_inversed = BoolProperty(
)
is_inversed: BoolProperty(
name="Inverse",
description="Turn the obstacle 'inside-out'. Enabling this option will make the inside solid parts"
" of this obstacle empty while everything outside of the obstacle will become solid."
@@ -44,8 +43,8 @@ class FlipFluidObstacleProperties(bpy.types.PropertyGroup):
" can prevent fluid from generating",
default=False,
options={'HIDDEN'},
); exec(conv("is_inversed"))
export_animated_mesh = BoolProperty(
)
export_animated_mesh: BoolProperty(
name="Export Animated Mesh",
description="Export this object as an animated mesh. Exporting animated meshes are"
" slower, only use when necessary. This option is required for any animation that"
@@ -54,16 +53,16 @@ class FlipFluidObstacleProperties(bpy.types.PropertyGroup):
" not needed for static objects",
default=False,
options={'HIDDEN'},
); exec(conv("export_animated_mesh"))
skip_reexport = BoolProperty(
name="Skip Mesh Re-Export",
)
skip_reexport: BoolProperty(
name="Skip Re-Export",
description="Skip re-exporting this mesh when starting or resuming"
" a bake. If this mesh has not been exported or is missing files,"
" the addon will automatically export the required files",
default=False,
options={'HIDDEN'},
); exec(conv("skip_reexport"))
force_reexport_on_next_bake = BoolProperty(
)
force_reexport_on_next_bake: BoolProperty(
name="Force Re-Export On Next Bake",
description="Override the 'Skip Re-Export' option and force this mesh to be"
" re-exported and updated on the next time a simulation start/resumes"
@@ -72,16 +71,16 @@ class FlipFluidObstacleProperties(bpy.types.PropertyGroup):
" This option is only applicable if 'Skip Re-Export' is enabled",
default=False,
options={'HIDDEN'},
); exec(conv("force_reexport_on_next_bake"))
friction = FloatProperty(
)
friction: FloatProperty(
name="Friction",
description="Amount of friction between the fluid and the surface"
" of the obstacle",
min=0.0, max=1.0,
default=0.0,
precision=2,
); exec(conv("friction"))
velocity_scale = FloatProperty(
)
velocity_scale: FloatProperty(
name="Velocity Scale",
description="Scale the object velocity by this amount. Values greater than 1.0"
" will exaggerate the velocity and the simulation will behave as if the object"
@@ -91,8 +90,8 @@ class FlipFluidObstacleProperties(bpy.types.PropertyGroup):
soft_min=0.0, soft_max=5.0,
default=1.0,
precision=2,
); exec(conv("velocity_scale"))
whitewater_influence = FloatProperty(
)
whitewater_influence: FloatProperty(
name="Whitewater Influence",
description="Scale the amount of whitewater generated near this"
" obstacle by this value. A value of 1.0 will generate the"
@@ -101,8 +100,8 @@ class FlipFluidObstacleProperties(bpy.types.PropertyGroup):
min=0.0,
default=1.0,
precision=2,
); exec(conv("whitewater_influence"))
dust_emission_strength = FloatProperty(
)
dust_emission_strength: FloatProperty(
name="Dust Emission Strength",
description="Scale the amount of whitewater dust particles generated"
" near this obstacle by this value. A value of 1.0 will generate the"
@@ -112,8 +111,8 @@ class FlipFluidObstacleProperties(bpy.types.PropertyGroup):
min=0.0,
default=1.0,
precision=2,
); exec(conv("dust_emission_strength"))
sheeting_strength = FloatProperty(
)
sheeting_strength: FloatProperty(
name="Sheeting Strength Multiplier",
description="Scale the amount of fluid sheeting strength against this"
" obstacle by this value. This parameter will only take effect if"
@@ -121,8 +120,8 @@ class FlipFluidObstacleProperties(bpy.types.PropertyGroup):
min=0.0,
default=1.0,
precision=2,
); exec(conv("sheeting_strength"))
mesh_expansion = FloatProperty(
)
mesh_expansion: FloatProperty(
name="Expand Geometry",
description="Expand the obstacle mesh by this value. This setting"
" can be used to prevent fluid from slipping through small"
@@ -134,22 +133,22 @@ class FlipFluidObstacleProperties(bpy.types.PropertyGroup):
soft_min=-0.05, soft_max=0.05,
step=0.01,
precision=5,
); exec(conv("mesh_expansion"))
property_registry = PointerProperty(
)
property_registry: PointerProperty(
name="Obstacle Property Registry",
description="",
type=preset_properties.PresetRegistry,
); exec(conv("property_registry"))
)
disabled_in_viewport_tooltip = BoolProperty(
disabled_in_viewport_tooltip: BoolProperty(
name="Object Disabled in Viewport",
description="This obstacle object is currently disabled in the viewport within the"
" outliner (Monitor Icon) and will not be included in the simulation. If you"
" want the object hidden in the viewport, but still have the object included in the"
" simulation, use the outliner Hide in Viewport option instead (Eye Icon)",
default=True,
); exec(conv("disabled_in_viewport_tooltip"))
)
@@ -25,32 +25,31 @@ from ..utils import version_compatibility_utils as vcu
class FlipFluidOutflowProperties(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
is_enabled = BoolProperty(
is_enabled: BoolProperty(
name="Enabled",
description="Object is active in the fluid simulation",
default=True,
); exec(conv("is_enabled"))
remove_fluid = BoolProperty(
)
remove_fluid: BoolProperty(
name="Remove Fluid",
description="Enable removing fluid particles from the domain",
default=True,
); exec(conv("remove_fluid"))
remove_whitewater = bpy.props.BoolProperty(
)
remove_whitewater: bpy.props.BoolProperty(
name="Remove Whitewater",
description="Enable removing whitewater particles from the domain",
default=True,
); exec(conv("remove_whitewater"))
is_inversed = BoolProperty(
)
is_inversed: BoolProperty(
name="Inverse",
description="Turn the outflow object 'inside-out'. If enabled,"
" the outflow will remove fluid that is outside of the mesh"
" instead of removing fluid that is inside of the mesh",
default=False,
options={'HIDDEN'},
); exec(conv("is_inversed"))
export_animated_mesh = bpy.props.BoolProperty(
)
export_animated_mesh: bpy.props.BoolProperty(
name="Export Animated Mesh",
description="Export this object as an animated mesh. Exporting animated meshes are"
" slower, only use when necessary. This option is required for any animation that"
@@ -59,16 +58,16 @@ class FlipFluidOutflowProperties(bpy.types.PropertyGroup):
" not needed for static objects",
default=False,
options={'HIDDEN'},
); exec(conv("export_animated_mesh"))
skip_reexport = BoolProperty(
name="Skip re-export",
)
skip_reexport: BoolProperty(
name="Skip Re-export",
description="Skip re-exporting this mesh when starting or resuming"
" a bake. If this mesh has not been exported or is missing files,"
" the addon will automatically export the required files",
default=False,
options={'HIDDEN'},
); exec(conv("skip_reexport"))
force_reexport_on_next_bake = BoolProperty(
)
force_reexport_on_next_bake: BoolProperty(
name="Force Re-Export On Next Bake",
description="Override the 'Skip Re-Export' option and force this mesh to be"
" re-exported and updated on the next time a simulation start/resumes"
@@ -77,22 +76,22 @@ class FlipFluidOutflowProperties(bpy.types.PropertyGroup):
" This option is only applicable if 'Skip Re-Export' is enabled",
default=False,
options={'HIDDEN'},
); exec(conv("force_reexport_on_next_bake"))
property_registry = PointerProperty(
)
property_registry: PointerProperty(
name="Outflow Property Registry",
description="",
type=preset_properties.PresetRegistry,
); exec(conv("property_registry"))
)
disabled_in_viewport_tooltip = BoolProperty(
disabled_in_viewport_tooltip: BoolProperty(
name="Object Disabled in Viewport",
description="This outflow object is currently disabled in the viewport within the"
" outliner (Monitor Icon) and will not be included in the simulation. If you"
" want the object hidden in the viewport, but still have the object included in the"
" simulation, use the outliner Hide in Viewport option instead (Eye Icon)",
default=True,
); exec(conv("disabled_in_viewport_tooltip"))
)
@@ -50,32 +50,22 @@ def get_addon_preferences(context=None):
context = bpy.context
prefs = vcu.get_blender_preferences(context)
if vcu.is_blender_42():
id_name = base_package
return prefs.addons[id_name].preferences
else:
id_name = __name__.split(".")[0]
if id_name not in prefs.addons:
global FAKE_PREFERENCES
return FAKE_PREFERENCES
return prefs.addons[id_name].preferences
id_name = base_package
return prefs.addons[id_name].preferences
class FLIPFluidGPUDevice(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
name = StringProperty(); exec(conv("name"))
description = StringProperty(); exec(conv("description"))
score = FloatProperty(); exec(conv("score"))
name: StringProperty()
description: StringProperty()
score: FloatProperty()
class FLIPFluidColorMixbox(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
color = FloatVectorProperty(default=(0, 0, 0), subtype='COLOR', description="Color mix using Mixbox blending"); exec(conv("color"))
color: FloatVectorProperty(default=(0, 0, 0), subtype='COLOR', description="Color mix using Mixbox blending")
class FLIPFluidColorRGB(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
color = FloatVectorProperty(default=(0, 0, 0), subtype='COLOR', description="Color mix using basic RGB blending"); exec(conv("color"))
color: FloatVectorProperty(default=(0, 0, 0), subtype='COLOR', description="Color mix using basic RGB blending")
def update_helper_category_name(self, context):
@@ -102,27 +92,23 @@ def update_helper_category_name(self, context):
class FLIPFluidAddonPreferences(bpy.types.AddonPreferences):
global FAKE_PREFERENCES
if vcu.is_blender_42():
bl_idname = base_package
else:
bl_idname = __name__.split(".")[0]
bl_idname = base_package
option_path_supports_blend_relative = set()
if vcu.is_blender_45():
# required for relative path support in Blender 4.5+
# https://docs.blender.org/api/4.5/bpy_types_enum_items/property_flag_items.html#rna-enum-property-flag-items
option_path_supports_blend_relative = {'PATH_SUPPORTS_BLEND_RELATIVE'}
# required for relative path support in Blender 4.5+
# https://docs.blender.org/api/4.5/bpy_types_enum_items/property_flag_items.html#rna-enum-property-flag-items
option_path_supports_blend_relative = {'PATH_SUPPORTS_BLEND_RELATIVE'}
preferences_menu_view_mode = EnumProperty(
preferences_menu_view_mode: EnumProperty(
name="Preferences Menu View",
description="Select the preferences category to view",
items=types.preferences_menu_view_modes,
default='PREFERENCES_MENU_VIEW_GENERAL',
options={'HIDDEN'},
); exec(vcu.convert_attribute_to_28("preferences_menu_view_mode"))
)
enable_helper = BoolProperty(
enable_helper: BoolProperty(
name="Enable Helper Sidebar",
description="Enable the FLIP Fluid helper menu in the 3D view sidebar."
" This menu contains operators to help with workflow and simulation setup",
@@ -130,19 +116,17 @@ class FLIPFluidAddonPreferences(bpy.types.AddonPreferences):
update=lambda self, context: self._update_enable_helper(context),
options={'HIDDEN'},
)
exec(vcu.convert_attribute_to_28("enable_helper"))
FAKE_PREFERENCES.enable_helper = True
helper_category_name = StringProperty(
helper_category_name: StringProperty(
name="Panel Category",
description="Choose a category for the FLIP Fluids helper panel tab in the sidebar",
default="FLIP Fluids",
update=lambda self, context: self._update_helper_category_name(context),
)
exec(vcu.convert_attribute_to_28("helper_category_name"))
FAKE_PREFERENCES.helper_category_name = "FLIP Fluids"
engine_debug_mode = BoolProperty(
engine_debug_mode: BoolProperty(
name="Engine Debug Mode",
description="Enable to run simulation engine in debug mode (slower, but is able to"
" generate crash errors). Disabling can speed up simulation by 10% - 15%, but if"
@@ -152,10 +136,9 @@ class FLIPFluidAddonPreferences(bpy.types.AddonPreferences):
" situation. Running with debug mode on or off will not affect simulation results",
default=False,
);
exec(vcu.convert_attribute_to_28("engine_debug_mode"))
FAKE_PREFERENCES.engine_debug_mode = False
enable_blend_file_logging = BoolProperty(
enable_blend_file_logging: BoolProperty(
name="Save Blender Installation and Simulation Info to Blend File",
description="If enabled, save info about your Blender installation and simulation set up into the"
" Blend file. Saving this info into the Blend file helps improve turnaround time when requesting"
@@ -165,46 +148,41 @@ class FLIPFluidAddonPreferences(bpy.types.AddonPreferences):
" additional items and info when requesting support",
default=True,
);
exec(vcu.convert_attribute_to_28("enable_blend_file_logging"))
FAKE_PREFERENCES.enable_blend_file_logging = True
enable_experimental_build_warning = BoolProperty(
enable_experimental_build_warning: BoolProperty(
name="Show Experimental Build Warning",
description="Disable to hide the experimental build warning/notification in the Physics menu",
default=True,
);
exec(vcu.convert_attribute_to_28("enable_experimental_build_warning"))
FAKE_PREFERENCES.enable_experimental_build_warning = True
enable_extra_features = BoolProperty(
enable_extra_features: BoolProperty(
name="Enable Extra Features",
description="Enable to unlock extra features"
" that may be considered unstable for rendering, baking, and exporting due to current bugs in Blender."
" Rendering issues can be completely avoided by rendering from the command line",
default=True,
);
exec(vcu.convert_attribute_to_28("enable_extra_features"))
FAKE_PREFERENCES.enable_extra_features = False
enable_support_tools = BoolProperty(
enable_support_tools: BoolProperty(
name="Enable Technical Support Tools",
description="Used by the developers to assist in technical support requests",
default=False,
);
exec(vcu.convert_attribute_to_28("enable_support_tools"))
FAKE_PREFERENCES.enable_support_tools = False
cmd_save_blend_file_before_launch = BoolProperty(
cmd_save_blend_file_before_launch: BoolProperty(
name="Autosave Blend file before launching command line operators",
description="Command line operators require the Blend file to be saved for changes to take effect when using command"
" line operators. If enabled, the Blend file will be automatically saved when using command line operators so that"
" manual saving is not necessary",
default=True,
);
exec(vcu.convert_attribute_to_28("cmd_save_blend_file_before_launch"))
FAKE_PREFERENCES.cmd_save_blend_file_before_launch = True
cmd_bake_max_attempts = IntProperty(
cmd_bake_max_attempts: IntProperty(
name="Max Attempts",
description="When using the command line baking operator, if a bake fails due to a crash or an error, attempt"
" to automatically re-launch and resume the baking process. This value is the maximum number of attempts that"
@@ -213,20 +191,18 @@ class FLIPFluidAddonPreferences(bpy.types.AddonPreferences):
default=5,
options={'HIDDEN'},
)
exec(vcu.convert_attribute_to_28("cmd_bake_max_attempts"))
FAKE_PREFERENCES.cmd_bake_max_attempts = False
enable_bake_alarm = BoolProperty(
enable_bake_alarm: BoolProperty(
name="Play alarm after simulation finishes",
description="Play an alarm sound when the simulation baking process completes. The alarm will sound on both a"
" successful bake as well as a bake where an error is encountered. This feature may not work correctly if"
" a crash is encountered",
default=False,
);
exec(vcu.convert_attribute_to_28("enable_bake_alarm"))
FAKE_PREFERENCES.enable_experimental_build_warning = False
enable_presets = BoolProperty(
enable_presets: BoolProperty(
name="Enable Presets",
description="Presets are a deprecated feature that will no longer be updated. Enable to use the older preset"
" features, but be aware that you may encounter bugs or issues. Use at your own risk. Blender must be"
@@ -234,82 +210,71 @@ class FLIPFluidAddonPreferences(bpy.types.AddonPreferences):
default=False,
options={'HIDDEN'},
)
exec(vcu.convert_attribute_to_28("enable_presets"))
FAKE_PREFERENCES.enable_presets = False
selected_gpu_device = EnumProperty(
selected_gpu_device: EnumProperty(
name="GPU Compute Device",
description="Device that will be used for GPU acceleration features",
items=lambda self, context=None: self._get_gpu_device_enums(context),
)
exec(vcu.convert_attribute_to_28("selected_gpu_device"))
FAKE_PREFERENCES.selected_gpu_device = None
gpu_devices = CollectionProperty(type=FLIPFluidGPUDevice)
exec(vcu.convert_attribute_to_28("gpu_devices"))
gpu_devices: CollectionProperty(type=FLIPFluidGPUDevice)
FAKE_PREFERENCES.gpu_devices = []
is_gpu_devices_initialized = BoolProperty(False)
exec(vcu.convert_attribute_to_28("is_gpu_devices_initialized"))
is_gpu_devices_initialized: BoolProperty(False)
FAKE_PREFERENCES.is_gpu_devices_initialized = False
show_mixbox_menu = BoolProperty(default=False)
exec(vcu.convert_attribute_to_28("show_mixbox_menu"))
show_mixbox_menu: BoolProperty(default=False)
FAKE_PREFERENCES.show_mixbox_menu = False
is_mixbox_installation_error = BoolProperty(default=False)
exec(vcu.convert_attribute_to_28("is_mixbox_installation_error"))
is_mixbox_installation_error: BoolProperty(default=False)
FAKE_PREFERENCES.is_mixbox_installation_error = False
mixbox_installation_error_message = StringProperty(default="")
exec(vcu.convert_attribute_to_28("mixbox_installation_error_message"))
mixbox_installation_error_message: StringProperty(default="")
FAKE_PREFERENCES.mixbox_installation_error_message = ""
mixbox_color1 = FloatVectorProperty(
mixbox_color1: FloatVectorProperty(
name="Color 1",
subtype='COLOR',
default=(0.0, 0.0, 0.24),
min=0.0, max=1.0,
description="Color Input 1",
update=lambda self, context: self._update_mixbox_color_test(context),
); exec(vcu.convert_attribute_to_28("mixbox_color1"))
)
mixbox_color2 = FloatVectorProperty(
mixbox_color2: FloatVectorProperty(
name="Color 2",
subtype='COLOR',
default=(0.7, 0.7, 0.0),
min=0.0, max=1.0,
description="Color Input 2",
update=lambda self, context: self._update_mixbox_color_test(context),
); exec(vcu.convert_attribute_to_28("mixbox_color2"))
)
num_gradient_samples = IntProperty(default=25)
exec(vcu.convert_attribute_to_28("num_gradient_samples"))
num_gradient_samples: IntProperty(default=25)
FAKE_PREFERENCES.num_gradient_samples = 0
mixbox_gradient_result = CollectionProperty(type=FLIPFluidColorMixbox)
exec(vcu.convert_attribute_to_28("mixbox_gradient_result"))
mixbox_gradient_result: CollectionProperty(type=FLIPFluidColorMixbox)
FAKE_PREFERENCES.mixbox_gradient_result = []
rgb_gradient_result = CollectionProperty(type=FLIPFluidColorRGB)
exec(vcu.convert_attribute_to_28("rgb_gradient_result"))
rgb_gradient_result: CollectionProperty(type=FLIPFluidColorRGB)
FAKE_PREFERENCES.rgb_gradient_result = []
test_mixbox_expanded = BoolProperty(
test_mixbox_expanded: BoolProperty(
default=False,
update=lambda self, context: self._update_mixbox_color_test(context)
);
exec(vcu.convert_attribute_to_28("test_mixbox_expanded"))
preset_library_install_mode = EnumProperty(
preset_library_install_mode: EnumProperty(
name="Preset Library Install Method",
description="Installation Method",
items=types.preset_library_install_modes,
default='PRESET_LIBRARY_INSTALL_ZIP',
options={'HIDDEN'},
); exec(vcu.convert_attribute_to_28("preset_library_install_mode"))
)
preset_library_install_location = StringProperty(
preset_library_install_location: StringProperty(
name="",
description="Select a location to install the Preset Scenes Library."
" This should be a location on your system where you have read and write file permissions",
@@ -317,21 +282,17 @@ class FLIPFluidAddonPreferences(bpy.types.AddonPreferences):
subtype='DIR_PATH',
options=option_path_supports_blend_relative,
);
exec(vcu.convert_attribute_to_28("preset_library_install_location"))
FAKE_PREFERENCES.preset_library_install_location = ""
is_preset_library_installation_error = BoolProperty(default=False)
exec(vcu.convert_attribute_to_28("is_preset_library_installation_error"))
is_preset_library_installation_error: BoolProperty(default=False)
FAKE_PREFERENCES.is_preset_library_installation_error = False
preset_library_installation_error_message = StringProperty(default="")
exec(vcu.convert_attribute_to_28("preset_library_installation_error_message"))
preset_library_installation_error_message: StringProperty(default="")
FAKE_PREFERENCES.preset_library_installation_error_message = ""
preset_library_installations_expanded = BoolProperty(default=True);
exec(vcu.convert_attribute_to_28("preset_library_installations_expanded"))
preset_library_installations_expanded: BoolProperty(default=True);
dismiss_T88811_crash_warning = BoolProperty(
dismiss_T88811_crash_warning: BoolProperty(
name="Dismiss render crash bug warnings",
description="Dismiss warnings in UI when features are enabled that can trigger a"
" bug in Blender (T88811) that can cause frequent render crashes or incorrect"
@@ -340,10 +301,9 @@ class FLIPFluidAddonPreferences(bpy.types.AddonPreferences):
" cmd render. This option can be reset in the addon preferences",
default=False,
);
exec(vcu.convert_attribute_to_28("dismiss_T88811_crash_warning"))
FAKE_PREFERENCES.dismiss_T88811_crash_warning = False
dismiss_persistent_data_render_warning = BoolProperty(
dismiss_persistent_data_render_warning: BoolProperty(
name="Dismiss persistent data warnings",
description="Dismiss warnings in UI when the Cycles Persistent Data option is enabled."
" This render option is not compatible with the simulation meshes and can cause render"
@@ -353,10 +313,9 @@ class FLIPFluidAddonPreferences(bpy.types.AddonPreferences):
" automatically launch a cmd render. This option can be reset in the addon preferences",
default=False,
);
exec(vcu.convert_attribute_to_28("dismiss_persistent_data_render_warning"))
FAKE_PREFERENCES.dismiss_persistent_data_render_warning = False
dismiss_rtx_driver_warning = BoolProperty(
dismiss_rtx_driver_warning: BoolProperty(
name="Dismiss NVIDIA GeForce RTX Driver Warning",
description="Dismiss warning in the FLIP Fluids preferences menu related to a recent NVIDIA"
" GeForce RTX 'Game Ready Driver' update that may cause Blender to crash frequently when baking"
@@ -365,10 +324,9 @@ class FLIPFluidAddonPreferences(bpy.types.AddonPreferences):
" creation software",
default=False,
);
exec(vcu.convert_attribute_to_28("dismiss_rtx_driver_warning"))
FAKE_PREFERENCES.dismiss_rtx_driver_warning = False
dismiss_export_animated_mesh_parented_relation_hint = BoolProperty(
dismiss_export_animated_mesh_parented_relation_hint: BoolProperty(
name="Dismiss 'Export Animated Mesh' parented relation hint",
description="Dismiss hints about enabling 'Export Animated Mesh' in the FLIP object UI"
" when parented relations are detected. The 'Export Animated Mesh' option is required"
@@ -377,10 +335,9 @@ class FLIPFluidAddonPreferences(bpy.types.AddonPreferences):
" This option is not needed for static objects",
default=False,
);
exec(vcu.convert_attribute_to_28("dismiss_export_animated_mesh_parented_relation_hint"))
FAKE_PREFERENCES.dismiss_export_animated_mesh_parented_relation_hint = False
enable_tabbed_domain_settings_view = BoolProperty(
enable_tabbed_domain_settings_view: BoolProperty(
name="Enable Tabbed Domain Settings",
description="Enable tabbed domain settings view. If enabled, domain panel categories will be displayed"
" using a tab header selector. If disabled, the classic view will display all domain panel categories"
@@ -388,7 +345,6 @@ class FLIPFluidAddonPreferences(bpy.types.AddonPreferences):
default=True,
options={'HIDDEN'},
)
exec(vcu.convert_attribute_to_28("enable_tabbed_domain_settings_view"))
FAKE_PREFERENCES.enable_tabbed_domain_settings_view = True
@@ -482,12 +438,8 @@ class FLIPFluidAddonPreferences(bpy.types.AddonPreferences):
icon="URL"
).url = "https://scrtwpns.com/mixbox/"
return
if not vcu.is_blender_293():
box.label(text="Blender 2.93 or later is required for this feature", icon='ERROR')
column = box.column(align=True)
column.enabled = vcu.is_blender_293()
if not is_installed:
subbox = column.box()
sub_column = subbox.column(align=True)
@@ -624,9 +576,6 @@ class FLIPFluidAddonPreferences(bpy.types.AddonPreferences):
box = self.layout.box()
box.label(text="Install Preset Scenes Library:")
if not vcu.is_blender_33():
box.label(text="Blender 3.3 or later is required for this feature", icon="ERROR")
subbox = box.box()
column = subbox.column(align=True)
column.label(text="This is an initial test phase for the new Preset Library integration into the", icon="INFO")
@@ -638,7 +587,6 @@ class FLIPFluidAddonPreferences(bpy.types.AddonPreferences):
).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Preset-Library-Installation-and-Uninstallation"
column = box.column(align=True)
column.enabled = vcu.is_blender_33()
row = column.row()
row.prop(self, "preset_library_install_mode", expand=True)
@@ -812,15 +760,14 @@ class FLIPFluidAddonPreferences(bpy.types.AddonPreferences):
row.label(text="")
helper_column.separator()
if vcu.is_blender_28():
box = self.layout.box()
box.enabled = is_installation_complete
helper_column = box.column(align=True)
helper_column.label(text="Sounds:")
row = helper_column.row(align=True)
row.alignment = 'LEFT'
row.prop(self, "enable_bake_alarm")
row.operator("flip_fluid_operators.test_bake_alarm", icon='PLAY_SOUND')
box = self.layout.box()
box.enabled = is_installation_complete
helper_column = box.column(align=True)
helper_column.label(text="Sounds:")
row = helper_column.row(align=True)
row.alignment = 'LEFT'
row.prop(self, "enable_bake_alarm")
row.operator("flip_fluid_operators.test_bake_alarm", icon='PLAY_SOUND')
box = self.layout.box()
box.enabled = is_installation_complete
@@ -981,8 +928,8 @@ class FLIPFluidAddonPreferences(bpy.types.AddonPreferences):
).url = "https://www.instagram.com/flip.fluids/"
row.operator(
"wm.url_open",
text="Twitter",
).url = "https://twitter.com/flipfluids"
text="X (Twitter)",
).url = "https://x.com/flipfluids"
row.operator(
"wm.url_open",
text="Facebook",
@@ -37,18 +37,16 @@ DUMMY_DOMAIN_OBJECT = None
class PresetRegistryProperty(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
path = StringProperty(); exec(conv("path"))
label = StringProperty(); exec(conv("label"))
is_key = BoolProperty(); exec(conv("is_key"))
key_path = StringProperty(); exec(conv("key_path"))
key_value = StringProperty(); exec(conv("key_value"))
group_id = IntProperty(); exec(conv("group_id"))
path: StringProperty()
label: StringProperty()
is_key: BoolProperty()
key_path: StringProperty()
key_value: StringProperty()
group_id: IntProperty()
class PresetRegistry(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
properties = CollectionProperty(type=PresetRegistryProperty); exec(conv("properties"))
properties: CollectionProperty(type=PresetRegistryProperty)
def clear(self):
@@ -75,28 +73,27 @@ class PresetRegistry(bpy.types.PropertyGroup):
class NewPresetPackageSettings(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
name = StringProperty(
name: StringProperty(
name="",
description="Preset package name",
default="New Package"
); exec(conv("name"))
author = StringProperty(
)
author: StringProperty(
name="",
description="Preset package author (optional)",
default=""
); exec(conv("author"))
description = StringProperty(
)
description: StringProperty(
name="",
description="Preset package description (optional)",
default=""
); exec(conv("description"))
use_custom_icons = BoolProperty(
)
use_custom_icons: BoolProperty(
name="",
description="Use custom icon images for package presets. "
"Images should be 256x256 resolution and PNG format",
default=False
); exec(conv("use_custom_icons"))
)
def reset(self):
@@ -116,12 +113,11 @@ class NewPresetPackageSettings(bpy.types.PropertyGroup):
class DeletePresetPackageSettings(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
package = EnumProperty(
package: EnumProperty(
name="Remove Package",
description="Select a package to remove",
items=preset_library.get_deletable_package_enums,
); exec(conv("package"))
)
def reset(self):
@@ -129,12 +125,11 @@ class DeletePresetPackageSettings(bpy.types.PropertyGroup):
class PresetPropertyUI(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
path = StringProperty(default=""); exec(conv("path"))
label = StringProperty(default=""); exec(conv("label"))
value = StringProperty(default=""); exec(conv("value"))
enabled = BoolProperty(default=True); exec(conv("enabled"))
dummy_prop = BoolProperty(default=True); exec(conv("dummy_prop"))
path: StringProperty(default="")
label: StringProperty(default="")
value: StringProperty(default="")
enabled: BoolProperty(default=True)
dummy_prop: BoolProperty(default=True)
def set_value(self, value):
@@ -148,17 +143,16 @@ class PresetPropertyUI(bpy.types.PropertyGroup):
class PresetPropertiesUI(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
simulation = CollectionProperty(type=PresetPropertyUI); exec(conv("simulation"))
render = CollectionProperty(type=PresetPropertyUI); exec(conv("render"))
surface = CollectionProperty(type=PresetPropertyUI); exec(conv("surface"))
whitewater = CollectionProperty(type=PresetPropertyUI); exec(conv("whitewater"))
world = CollectionProperty(type=PresetPropertyUI); exec(conv("world"))
materials = CollectionProperty(type=PresetPropertyUI); exec(conv("materials"))
advanced = CollectionProperty(type=PresetPropertyUI); exec(conv("advanced"))
debug = CollectionProperty(type=PresetPropertyUI); exec(conv("debug"))
stats = CollectionProperty(type=PresetPropertyUI); exec(conv("stats"))
is_initialized = BoolProperty(default=False); exec(conv("is_initialized"))
simulation: CollectionProperty(type=PresetPropertyUI)
render: CollectionProperty(type=PresetPropertyUI)
surface: CollectionProperty(type=PresetPropertyUI)
whitewater: CollectionProperty(type=PresetPropertyUI)
world: CollectionProperty(type=PresetPropertyUI)
materials: CollectionProperty(type=PresetPropertyUI)
advanced: CollectionProperty(type=PresetPropertyUI)
debug: CollectionProperty(type=PresetPropertyUI)
stats: CollectionProperty(type=PresetPropertyUI)
is_initialized: BoolProperty(default=False)
def initialize(self):
@@ -406,24 +400,23 @@ class PresetPropertiesUI(bpy.types.PropertyGroup):
class NewPresetSettings(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
package = EnumProperty(
package: EnumProperty(
name="Preset Package",
description="Add preset to this package",
items=preset_library.get_user_package_enums,
); exec(conv("package"))
name = StringProperty(
)
name: StringProperty(
name="Name",
description="Preset name",
default="New Preset"
); exec(conv("name"))
description = StringProperty(
)
description: StringProperty(
name="Description",
description="Preset description (optional)",
default=""
); exec(conv("description"))
icon = StringProperty(
)
icon: StringProperty(
name="Icon",
description="Icons should be 256x256 resolution and in PNG format."
" Images must be imported into the Blender UV/Image Editor before"
@@ -431,87 +424,87 @@ class NewPresetSettings(bpy.types.PropertyGroup):
" this popup",
default="",
update=lambda self, context=None: self._update_icon(context),
); exec(conv("icon"))
display_icon = EnumProperty(
)
display_icon: EnumProperty(
name="Preset Icon",
description="",
items=lambda self, context=None: self._get_display_icon_enum(context),
); exec(conv("display_icon"))
export_simulation = BoolProperty(
)
export_simulation: BoolProperty(
name="Simulation",
description="Export 'FLIP Fluid Simulation' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_simulation"))
export_display = BoolProperty(
)
export_display: BoolProperty(
name="Display Settings",
description="Export 'FLIP Fluid Display Settings' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_display"))
export_surface = BoolProperty(
)
export_surface: BoolProperty(
name="Surface",
description="Export 'FLIP Fluid Surface' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_surface"))
export_whitewater = BoolProperty(
)
export_whitewater: BoolProperty(
name="Whitewater",
description="Export 'FLIP Fluid Whitewater' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_whitewater"))
export_world = BoolProperty(
)
export_world: BoolProperty(
name="World",
description="Export 'FLIP Fluid World' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_world"))
export_materials = BoolProperty(
)
export_materials: BoolProperty(
name="Materials",
description="Export 'FLIP Fluid Materials' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_materials"))
export_advanced = BoolProperty(
)
export_advanced: BoolProperty(
name="Advanced",
description="Export 'FLIP Fluid Advanced' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_advanced"))
export_debug = BoolProperty(
)
export_debug: BoolProperty(
name="Debug",
description="Export 'FLIP Fluid Debug' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_debug"))
export_stats = BoolProperty(
)
export_stats: BoolProperty(
name="Stats",
description="Export 'FLIP Fluid Stats' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_stats"))
ui_sort = BoolProperty(
)
ui_sort: BoolProperty(
name="Sort Attributes",
description="Sort attributes by enabled/disabled",
default=False,
); exec(conv("ui_sort"))
current_display_panel = EnumProperty(
)
current_display_panel: EnumProperty(
name="Current Preset Display",
description="Current preset panel to display",
items=lambda self, context=None: self.get_preset_panel_selector_enums(context),
); exec(conv("current_display_panel"))
)
ui_properties = PointerProperty(type=PresetPropertiesUI); exec(conv("ui_properties"))
is_unedited = BoolProperty(default=True); exec(conv("is_unedited"))
ui_properties: PointerProperty(type=PresetPropertiesUI)
is_unedited: BoolProperty(default=True)
# If set to 'True', new preset menu will automatically select which
# panels to export by comparing current property values to system devault
# values.
# If set to 'False', new preset menu will start with a blank panel
# export selection.
autoselect_exported_panels = BoolProperty(default=False); exec(conv("autoselect_exported_panels"))
autoselect_exported_panels: BoolProperty(default=False)
def initialize(self):
@@ -768,18 +761,17 @@ class NewPresetSettings(bpy.types.PropertyGroup):
class DeletePresetSettings(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
package = EnumProperty(
package: EnumProperty(
name="Package",
description="Select preset package",
items=preset_library.get_user_package_enums,
); exec(conv("package"))
preset = EnumProperty(
)
preset: EnumProperty(
name="Remove Preset",
description="Select a preset to remove",
items=preset_library.get_deletable_preset_enums,
); exec(conv("preset"))
)
def reset(self):
@@ -811,45 +803,42 @@ class DeletePresetSettings(bpy.types.PropertyGroup):
class ExportPresetPackageSettings(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
option_path_supports_blend_relative = set()
if vcu.is_blender_45():
# required for relative path support in Blender 4.5+
# https://docs.blender.org/api/4.5/bpy_types_enum_items/property_flag_items.html#rna-enum-property-flag-items
option_path_supports_blend_relative = {'PATH_SUPPORTS_BLEND_RELATIVE'}
# required for relative path support in Blender 4.5+
# https://docs.blender.org/api/4.5/bpy_types_enum_items/property_flag_items.html#rna-enum-property-flag-items
option_path_supports_blend_relative = {'PATH_SUPPORTS_BLEND_RELATIVE'}
package = EnumProperty(
package: EnumProperty(
name="Export Package",
description="Select a package to export",
items=preset_library.get_exportable_package_enums,
update=lambda self, context: self._initialize_export_filename(),
); exec(conv("package"))
export_directory = StringProperty(
)
export_directory: StringProperty(
name="",
description="Preset package will be exported to this directory",
default=vcu.get_blender_preferences_temporary_directory(),
subtype='DIR_PATH',
options=option_path_supports_blend_relative,
); exec(conv("export_directory"))
export_filename = StringProperty(
)
export_filename: StringProperty(
name="",
description="Filename of exported package",
default="",
update=lambda self, context: self._initialize_export_filepath(),
); exec(conv("export_filename"))
export_filepath = StringProperty(
)
export_filepath: StringProperty(
name="",
description="",
default="",
subtype='FILE_PATH',
options=option_path_supports_blend_relative,
); exec(conv("export_filepath"))
create_subdirectories = BoolProperty(
)
create_subdirectories: BoolProperty(
name="Create Missing Subdirectories",
description="Create missing subdirectories if export directory does not exist",
default=True,
); exec(conv("create_subdirectories"))
)
def reset(self):
@@ -905,30 +894,28 @@ class ExportPresetPackageSettings(bpy.types.PropertyGroup):
class MaterialPropertyInfo(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
preset_id = StringProperty(); exec(conv("preset_id"))
loaded_id = StringProperty(); exec(conv("loaded_id"))
is_owner = BoolProperty(default=False); exec(conv("is_owner"))
preset_id: StringProperty()
loaded_id: StringProperty()
is_owner: BoolProperty(default=False)
class DisplayPresetInfoSettings(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
display_icon = EnumProperty(
display_icon: EnumProperty(
name="Preset Icon",
description="",
items=lambda self, context=None: self._get_display_icon_enum(context),
); exec(conv("display_icon"))
current_display_panel = EnumProperty(
)
current_display_panel: EnumProperty(
name="Current Preset Display",
description="Current preset panel to display",
items=lambda self, context=None: self.get_preset_panel_selector_enums(context),
update=lambda self, context: self._initialize_dummy_domain_values(),
); exec(conv("current_display_panel"))
)
identifier = StringProperty(default=""); exec(conv("identifier"))
ui_properties = PointerProperty(type=PresetPropertiesUI); exec(conv("ui_properties"))
loaded_materials = CollectionProperty(type=MaterialPropertyInfo); exec(conv("loaded_materials"))
identifier: StringProperty(default="")
ui_properties: PointerProperty(type=PresetPropertiesUI)
loaded_materials: CollectionProperty(type=MaterialPropertyInfo)
def initialize(self):
@@ -1055,34 +1042,31 @@ class DisplayPresetInfoSettings(bpy.types.PropertyGroup):
class PresetProperty(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
path = StringProperty(); exec(conv("path"))
value = StringProperty(); exec(conv("value"))
path: StringProperty()
value: StringProperty()
class PresetInfo(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
name = StringProperty(); exec(conv("name"))
description = StringProperty(); exec(conv("description"))
identifier = StringProperty(); exec(conv("identifier"))
is_system_preset = BoolProperty(); exec(conv("is_system_preset"))
uid = IntProperty(); exec(conv("uid"))
icon_id = IntProperty(default=-1); exec(conv("icon_id"))
material_blend = StringProperty(default=""); exec(conv("material_blend"))
properties = CollectionProperty(type=PresetProperty); exec(conv("properties"))
name: StringProperty()
description: StringProperty()
identifier: StringProperty()
is_system_preset: BoolProperty()
uid: IntProperty()
icon_id: IntProperty(default=-1)
material_blend: StringProperty(default="")
properties: CollectionProperty(type=PresetProperty)
class PresetPackageInfo(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
name = StringProperty(); exec(conv("name"))
author = StringProperty(); exec(conv("author"))
description = StringProperty(); exec(conv("description"))
identifier = StringProperty(); exec(conv("identifier"))
is_system_package = BoolProperty(); exec(conv("is_system_package"))
is_default_user_package = BoolProperty(); exec(conv("is_default_user_package"))
use_custom_icons = BoolProperty(); exec(conv("use_custom_icons"))
uid = IntProperty(); exec(conv("uid"))
presets = CollectionProperty(type=PresetInfo); exec(conv("presets"))
name: StringProperty()
author: StringProperty()
description: StringProperty()
identifier: StringProperty()
is_system_package: BoolProperty()
is_default_user_package: BoolProperty()
use_custom_icons: BoolProperty()
uid: IntProperty()
presets: CollectionProperty(type=PresetInfo)
@classmethod
@@ -1135,34 +1119,33 @@ class PresetPackageInfo(bpy.types.PropertyGroup):
class ImportPresetPackageSettings(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
package_filepath = StringProperty(
package_filepath: StringProperty(
name="",
description="Package zip file",
default="",
); exec(conv("package_filepath"))
selected_preset = EnumProperty(
)
selected_preset: EnumProperty(
name="Preset",
description="Select a package preset to view details",
items=lambda self, context=None: self.get_package_preset_enums(context),
update=lambda self, context: self._update_selected_package(context),
); exec(conv("selected_preset"))
display_icon = EnumProperty(
)
display_icon: EnumProperty(
name="Preset Icon",
description="",
items=lambda self, context=None: self._get_display_icon_enum(context),
); exec(conv("display_icon"))
current_display_panel = EnumProperty(
)
current_display_panel: EnumProperty(
name="Current Preset Display",
description="Current preset panel to display",
items=lambda self, context=None: self.get_preset_panel_selector_enums(context),
update=lambda self, context: self._initialize_dummy_domain_values(),
); exec(conv("current_display_panel"))
)
ui_properties = PointerProperty(type=PresetPropertiesUI); exec(conv("ui_properties"))
loaded_materials = CollectionProperty(type=MaterialPropertyInfo); exec(conv("loaded_materials"))
package_info = PointerProperty(type=PresetPackageInfo); exec(conv("package_info"))
ui_properties: PointerProperty(type=PresetPropertiesUI)
loaded_materials: CollectionProperty(type=MaterialPropertyInfo)
package_info: PointerProperty(type=PresetPackageInfo)
def initialize(self, data):
@@ -1330,36 +1313,35 @@ class ImportPresetPackageSettings(bpy.types.PropertyGroup):
class EditPresetSettings(bpy.types.PropertyGroup):
conv = vcu.convert_attribute_to_28
edit_package = EnumProperty(
edit_package: EnumProperty(
name="Preset Package",
description="Edit preset from this package",
items=preset_library.get_user_package_enums,
update=lambda self, context=None: self._update_edit_package(context),
); exec(conv("edit_package"))
edit_preset = EnumProperty(
)
edit_preset: EnumProperty(
name="Edit Preset",
description="Select a preset to edit",
items=lambda self, context=None: preset_library.get_package_preset_enums(self, context, self.edit_package),
update=lambda self, context=None: self._update_edit_preset(context),
); exec(conv("edit_preset"))
package = EnumProperty(
)
package: EnumProperty(
name="Preset Package",
description="Move preset to this package",
items=preset_library.get_user_package_enums,
); exec(conv("package"))
name = StringProperty(
)
name: StringProperty(
name="Name",
description="New preset name",
default="New Preset"
); exec(conv("name"))
description = StringProperty(
)
description: StringProperty(
name="Description",
description="New preset description (optional)",
default=""
); exec(conv("description"))
icon = StringProperty(
)
icon: StringProperty(
name="Icon",
description="Icons should be 256x256 resolution and in PNG format."
" Images must be imported into the Blender UV/Image Editor before"
@@ -1367,82 +1349,82 @@ class EditPresetSettings(bpy.types.PropertyGroup):
" this popup",
default="",
update=lambda self, context=None: self._update_icon(context),
); exec(conv("icon"))
display_icon = display_icon = EnumProperty(
)
display_icon: display_icon = EnumProperty(
name="Preset Icon",
description="",
items=lambda self, context=None: self._get_display_icon_enum(context),
); exec(conv("display_icon"))
export_simulation = BoolProperty(
)
export_simulation: BoolProperty(
name="Simulation",
description="Export 'FLIP Fluid Simulation' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_simulation"))
export_display = BoolProperty(
)
export_display: BoolProperty(
name="Display Settings",
description="Export 'FLIP Fluid Display Settings' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_display"))
export_surface = BoolProperty(
)
export_surface: BoolProperty(
name="Surface",
description="Export 'FLIP Fluid Surface' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_surface"))
export_whitewater = BoolProperty(
)
export_whitewater: BoolProperty(
name="Whitewater",
description="Export 'FLIP Fluid Whitewater' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_whitewater"))
export_world = BoolProperty(
)
export_world: BoolProperty(
name="World",
description="Export 'FLIP Fluid World' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_world"))
export_materials = BoolProperty(
)
export_materials: BoolProperty(
name="Materials",
description="Export 'FLIP Fluid Materials' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_materials"))
export_advanced = BoolProperty(
)
export_advanced: BoolProperty(
name="Advanced",
description="Export 'FLIP Fluid Advanced' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_advanced"))
export_debug = BoolProperty(
)
export_debug: BoolProperty(
name="Debug",
description="Export 'FLIP Fluid Debug' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_debug"))
export_stats = BoolProperty(
)
export_stats: BoolProperty(
name="Stats",
description="Export 'FLIP Fluid Stats' panel settings",
default=False,
update=lambda self, context=None: self._check_current_display_panel(context),
); exec(conv("export_stats"))
ui_sort = BoolProperty(
)
ui_sort: BoolProperty(
name="Sort Attributes",
description="Sort attributes by enabled/disabled",
default=False,
); exec(conv("ui_sort"))
current_display_panel = EnumProperty(
)
current_display_panel: EnumProperty(
name="Current Preset Display",
description="Current preset panel to display",
items=lambda self, context=None: self.get_preset_panel_selector_enums(context),
); exec(conv("current_display_panel"))
)
ui_properties = PointerProperty(type=PresetPropertiesUI); exec(conv("ui_properties"))
loaded_icon_image_name = StringProperty(""); exec(conv("loaded_icon_image_name"))
loaded_materials = CollectionProperty(type=MaterialPropertyInfo); exec(conv("loaded_materials"))
is_unedited = BoolProperty(default=True); exec(conv("is_unedited"))
ui_properties: PointerProperty(type=PresetPropertiesUI)
loaded_icon_image_name: StringProperty("")
loaded_materials: CollectionProperty(type=MaterialPropertyInfo)
is_unedited: BoolProperty(default=True)
def initialize(self):
@@ -267,6 +267,7 @@ def __update_surface_display_mode():
surface_cache.enable_color_attribute = dprops.surface.enable_color_attribute
surface_cache.enable_source_id_attribute = dprops.surface.enable_source_id_attribute
surface_cache.enable_viscosity_attribute = dprops.surface.enable_viscosity_attribute
surface_cache.enable_density_attribute = dprops.world.enable_density_attribute
surface_cache.enable_id_attribute = False
elif display_mode == 'DISPLAY_PREVIEW':
surface_cache.mesh_prefix = "preview"
@@ -281,6 +282,7 @@ def __update_surface_display_mode():
surface_cache.enable_color_attribute = False
surface_cache.enable_source_id_attribute = False
surface_cache.enable_viscosity_attribute = False
surface_cache.enable_density_attribute = False
surface_cache.enable_id_attribute = False
elif display_mode == 'DISPLAY_NONE':
surface_cache.mesh_prefix = "none"
@@ -295,6 +297,7 @@ def __update_surface_display_mode():
surface_cache.enable_color_attribute = False
surface_cache.enable_source_id_attribute = False
surface_cache.enable_viscosity_attribute = False
surface_cache.enable_density_attribute = False
surface_cache.enable_id_attribute = False
@@ -366,6 +369,7 @@ def __update_fluid_particle_display_mode():
particle_cache.enable_color_attribute = particle_props.enable_fluid_particle_color_attribute
particle_cache.enable_source_id_attribute = particle_props.enable_fluid_particle_source_id_attribute
particle_cache.enable_viscosity_attribute = dprops.surface.enable_viscosity_attribute
particle_cache.enable_density_attribute = dprops.world.enable_density_attribute
particle_cache.enable_id_attribute = particle_props.enable_fluid_particle_output
particle_cache.enable_uid_attribute = particle_props.enable_fluid_particle_uid_attribute
elif display_mode == 'DISPLAY_PREVIEW':
@@ -380,6 +384,7 @@ def __update_fluid_particle_display_mode():
particle_cache.enable_color_attribute = particle_props.enable_fluid_particle_color_attribute
particle_cache.enable_source_id_attribute = particle_props.enable_fluid_particle_source_id_attribute
particle_cache.enable_viscosity_attribute = dprops.surface.enable_viscosity_attribute
particle_cache.enable_density_attribute = dprops.world.enable_density_attribute
particle_cache.enable_id_attribute = particle_props.enable_fluid_particle_output
particle_cache.enable_uid_attribute = particle_props.enable_fluid_particle_uid_attribute
elif display_mode == 'DISPLAY_NONE':
@@ -394,6 +399,7 @@ def __update_fluid_particle_display_mode():
particle_cache.enable_color_attribute = False
particle_cache.enable_source_id_attribute = False
particle_cache.enable_viscosity_attribute = False
particle_cache.enable_density_attribute = False
particle_cache.enable_id_attribute = False
particle_cache.enable_uid_attribute = False
@@ -518,6 +524,10 @@ def __update_whitewater_display_mode():
cache.bubble.enable_viscosity_attribute = False
cache.spray.enable_viscosity_attribute = False
cache.dust.enable_viscosity_attribute = False
cache.foam.enable_density_attribute = False
cache.bubble.enable_density_attribute = False
cache.spray.enable_density_attribute = False
cache.dust.enable_density_attribute = False
elif display_mode == 'DISPLAY_PREVIEW':
cache.foam.mesh_prefix = "foam"
cache.bubble.mesh_prefix = "bubble"
@@ -571,6 +581,10 @@ def __update_whitewater_display_mode():
cache.bubble.enable_viscosity_attribute = False
cache.spray.enable_viscosity_attribute = False
cache.dust.enable_viscosity_attribute = False
cache.foam.enable_density_attribute = False
cache.bubble.enable_density_attribute = False
cache.spray.enable_density_attribute = False
cache.dust.enable_density_attribute = False
elif display_mode == 'DISPLAY_NONE':
cache.foam.mesh_prefix = "foam_none"
cache.bubble.mesh_prefix = "bubble_none"
@@ -624,6 +638,10 @@ def __update_whitewater_display_mode():
cache.bubble.enable_viscosity_attribute = False
cache.spray.enable_viscosity_attribute = False
cache.dust.enable_viscosity_attribute = False
cache.foam.enable_density_attribute = False
cache.bubble.enable_density_attribute = False
cache.spray.enable_density_attribute = False
cache.dust.enable_density_attribute = False
foam_pct, bubble_pct, spray_pct, dust_pct = __get_whitewater_display_percentages()
cache.foam.wwp_import_percentage = foam_pct
@@ -809,11 +827,9 @@ def frame_change_post(scene, depsgraph=None):
if not __is_domain_in_scene():
return
if is_rendering() and vcu.is_blender_28():
if is_rendering():
if not scene.render.use_lock_interface:
print("FLIP FLUIDS WARNING: The Blender interface should be locked during render to prevent render crashes (Blender > Render > Lock Interface).")
if not vcu.is_blender_281():
print("FLIP FLUIDS WARNING: Blender 2.80 contains a bug that can cause frequent render crashes and incorrect render results. Blender version 2.81 or higher is recommended.")
force_reload = False
frameno = get_current_render_frame()
@@ -1,3 +1,19 @@
# 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 bpy, os, time, sys
@@ -17,6 +33,11 @@ def check_cache_exists():
return True
def enable_outliner_visibility(bl_object):
bl_object.hide_viewport = False
bl_object.hide_render = False
def initialize_simulation_mesh_selection():
dprops = bpy.context.scene.flip_fluid.get_domain_properties()
hprops = bpy.context.scene.flip_fluid_helper
@@ -24,12 +45,24 @@ def initialize_simulation_mesh_selection():
print("Searching for simulation meshes:")
bpy.ops.object.select_all(action='DESELECT')
bl_domain = bpy.context.scene.flip_fluid.get_domain_object()
print("Searching for domain mesh...", end="")
if bl_domain is not None:
bl_domain.select_set(True)
enable_outliner_visibility(bl_domain)
bl_domain.name = "FLIP_Domain"
print(" FOUND <" + bl_domain.name + ">")
else:
print(" NOT FOUND")
num_export_meshes = 0
if hprops.alembic_export_surface:
print("Searching for fluid surface mesh...", end="")
bl_surface = dprops.mesh_cache.surface.get_cache_object()
if bl_surface is not None:
bl_surface.select_set(True)
enable_outliner_visibility(bl_surface)
num_export_meshes += 1
print(" FOUND <" + bl_surface.name + ">")
else:
@@ -43,6 +76,7 @@ def initialize_simulation_mesh_selection():
bl_fluid_particles = dprops.mesh_cache.particles.get_cache_object()
if bl_fluid_particles is not None:
bl_fluid_particles.select_set(True)
enable_outliner_visibility(bl_fluid_particles)
num_export_meshes += 1
print(" FOUND <" + bl_fluid_particles.name + ">")
else:
@@ -56,6 +90,7 @@ def initialize_simulation_mesh_selection():
bl_foam = dprops.mesh_cache.foam.get_cache_object()
if bl_foam is not None:
bl_foam.select_set(True)
enable_outliner_visibility(bl_foam)
num_export_meshes += 1
print(" FOUND <" + bl_foam.name + ">")
else:
@@ -69,6 +104,7 @@ def initialize_simulation_mesh_selection():
bl_bubble = dprops.mesh_cache.bubble.get_cache_object()
if bl_bubble is not None:
bl_bubble.select_set(True)
enable_outliner_visibility(bl_bubble)
num_export_meshes += 1
print(" FOUND <" + bl_bubble.name + ">")
else:
@@ -82,6 +118,7 @@ def initialize_simulation_mesh_selection():
bl_spray = dprops.mesh_cache.spray.get_cache_object()
if bl_spray is not None:
bl_spray.select_set(True)
enable_outliner_visibility(bl_spray)
num_export_meshes += 1
print(" FOUND <" + bl_spray.name + ">")
else:
@@ -95,6 +132,7 @@ def initialize_simulation_mesh_selection():
bl_dust = dprops.mesh_cache.dust.get_cache_object()
if bl_dust is not None:
bl_dust.select_set(True)
enable_outliner_visibility(bl_dust)
num_export_meshes += 1
print(" FOUND <" + bl_dust.name + ">")
else:
@@ -178,6 +216,40 @@ def set_geometry_nodes_alembic_velocity_export_motion_blur_scale(bl_object, scal
return 1.0
def initialize_empty_modifier_alembic_export_workaround():
# FLIP Fluids simulation meshes are only recognized by Blender for animated Alembic export
# if the meshes have a modifier. Depending on export settings, some meshes may not have any modifiers
# and will not be exported. To workaround this, we'll add a modifier that does nothing: a smooth modifier
# with 0 smoothing.
def add_0_smooth_modifier(target_object):
smooth_mod = target_object.modifiers.new("FF_AlembicSmooth", "SMOOTH")
smooth_mod.factor = 1.5
smooth_mod.iterations = 0
return smooth_mod
print("\nInitializing workarounds to Alembic exporter issues:")
bl_surface = dprops.mesh_cache.surface.get_cache_object()
if bl_surface is not None:
add_0_smooth_modifier(bl_surface)
bl_fluid_particles = dprops.mesh_cache.particles.get_cache_object()
if bl_fluid_particles is not None:
add_0_smooth_modifier(bl_fluid_particles)
bl_foam = dprops.mesh_cache.foam.get_cache_object()
if bl_foam is not None:
add_0_smooth_modifier(bl_foam)
bl_bubble = dprops.mesh_cache.bubble.get_cache_object()
if bl_bubble is not None:
add_0_smooth_modifier(bl_bubble)
bl_spray = dprops.mesh_cache.spray.get_cache_object()
if bl_spray is not None:
add_0_smooth_modifier(bl_spray)
bl_dust = dprops.mesh_cache.dust.get_cache_object()
if bl_dust is not None:
add_0_smooth_modifier(bl_dust)
print("Finished initializing workarounds to Alembic exporter issues.")
def initialize_velocity_export_and_attributes():
dprops = bpy.context.scene.flip_fluid.get_domain_properties()
hprops = bpy.context.scene.flip_fluid_helper
@@ -208,38 +280,46 @@ def initialize_velocity_export_and_attributes():
if bl_dust is not None:
dust_motion_blur_scale = get_geomety_nodes_motion_blur_scale(bl_dust)
print("\nRemoving motion blur render setup:")
print("\nReplacing motion blur render setup with Alembic export setup:")
bpy.ops.flip_fluid_operators.helper_remove_motion_blur('INVOKE_DEFAULT', resource_prefix="FF_GeometryNodes")
print("Finished removing motion blur render setup.")
print("Finished replacing motion blur render setup.")
if hprops.alembic_export_velocity:
print("\nInitializing Alembic velocity export setup:")
bpy.ops.flip_fluid_operators.helper_initialize_motion_blur('INVOKE_DEFAULT', resource_prefix="FF_AlembicVelocityExport")
resources_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
geometry_nodes_library = os.path.join(resources_path, "geometry_nodes", "geometry_nodes_library.blend")
bl_surface = dprops.mesh_cache.surface.get_cache_object()
if bl_surface is not None:
add_geometry_node_modifier(bl_surface, geometry_nodes_library, "FF_AlembicVelocityExportSurface")
value = set_geometry_nodes_alembic_velocity_export_motion_blur_scale(bl_surface, surface_motion_blur_scale)
print("Info: Set fluid surface Alembic velocity scale to " + '{0:.2f}'.format(value))
bl_fluid_particles = dprops.mesh_cache.particles.get_cache_object()
if bl_fluid_particles is not None:
add_geometry_node_modifier(bl_fluid_particles, geometry_nodes_library, "FF_AlembicVelocityExportFluidParticles")
value = set_geometry_nodes_alembic_velocity_export_motion_blur_scale(bl_fluid_particles, fluid_particles_motion_blur_scale)
print("Info: Set fluid particles Alembic velocity scale to " + '{0:.2f}'.format(value))
bl_foam = dprops.mesh_cache.foam.get_cache_object()
if bl_foam is not None:
add_geometry_node_modifier(bl_foam, geometry_nodes_library, "FF_AlembicVelocityExportFluidParticles")
value = set_geometry_nodes_alembic_velocity_export_motion_blur_scale(bl_foam, foam_motion_blur_scale)
print("Info: Set whitewater foam Alembic velocity scale to " + '{0:.2f}'.format(value))
bl_bubble = dprops.mesh_cache.bubble.get_cache_object()
if bl_bubble is not None:
add_geometry_node_modifier(bl_bubble, geometry_nodes_library, "FF_AlembicVelocityExportFluidParticles")
value = set_geometry_nodes_alembic_velocity_export_motion_blur_scale(bl_bubble, bubble_motion_blur_scale)
print("Info: Set whitewater bubble Alembic velocity scale to " + '{0:.2f}'.format(value))
bl_spray = dprops.mesh_cache.spray.get_cache_object()
if bl_spray is not None:
add_geometry_node_modifier(bl_spray, geometry_nodes_library, "FF_AlembicVelocityExportFluidParticles")
value = set_geometry_nodes_alembic_velocity_export_motion_blur_scale(bl_spray, spray_motion_blur_scale)
print("Info: Set whitewater spray Alembic velocity scale to " + '{0:.2f}'.format(value))
bl_dust = dprops.mesh_cache.dust.get_cache_object()
if bl_dust is not None:
add_geometry_node_modifier(bl_dust, geometry_nodes_library, "FF_AlembicVelocityExportFluidParticles")
value = set_geometry_nodes_alembic_velocity_export_motion_blur_scale(bl_dust, dust_motion_blur_scale)
print("Info: Set whitewater dust Alembic velocity scale to " + '{0:.2f}'.format(value))
print("Finished initializing Alembic velocity export setup.")
@@ -474,6 +554,7 @@ retval = initialize_simulation_mesh_selection()
if not retval:
exit()
initialize_empty_modifier_alembic_export_workaround()
initialize_velocity_export_and_attributes()
check_cache_velocity_data()
@@ -544,4 +625,4 @@ bpy.ops.wm.alembic_export(
start=frame_start,
end=frame_end,
vcolors=hprops.alembic_export_color,
global_scale=global_scale)
global_scale=global_scale)
@@ -0,0 +1,96 @@
# 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 bpy, ctypes, os, json, platform, traceback
def get_flip_fluids_alembic_exporter_lib_filepath():
executable_name = ""
system = platform.system()
if system == "Windows":
lib_name = "libffalembicengine.dll"
elif system == "Darwin":
lib_name = "libffalembicengine.dylib"
elif system == "Linux":
lib_name = "libffalembicengine.so"
lib_path = os.path.dirname(os.path.realpath(__file__))
lib_path = os.path.dirname(os.path.dirname(lib_path))
lib_path = os.path.join(lib_path, "ffengine", "lib", lib_name)
if not os.path.isfile(lib_path):
return None, "Missing Alembic export engine library <" + lib_path + ">"
return lib_path, None
def get_export_frame_range():
frame_start = bpy.context.scene.frame_start
frame_end = bpy.context.scene.frame_end
hprops = bpy.context.scene.flip_fluid_helper
if hprops.alembic_frame_range_mode == 'FRAME_RANGE_CUSTOM':
frame_start = hprops.alembic_frame_range_custom.value_min
frame_end = hprops.alembic_frame_range_custom.value_max
return frame_start, frame_end
def flip_fluids_alembic_export():
hprops = bpy.context.scene.flip_fluid_helper
dprops = bpy.context.scene.flip_fluid.get_domain_properties()
input_cache_directory = dprops.cache.get_cache_abspath()
output_alembic_filepath = hprops.alembic_output_filepath
frame_start, frame_end = get_export_frame_range()
export_config = {}
export_config['cache_directory'] = input_cache_directory
export_config['alembic_filepath'] = output_alembic_filepath
export_config['frame_start'] = frame_start
export_config['frame_end'] = frame_end
json_string = json.dumps(export_config, indent=4)
b_json_string = json_string.encode('utf-8')
exporter_library_filepath, error_message = get_flip_fluids_alembic_exporter_lib_filepath()
if error_message is not None:
print("\n***ERROR: Unabled to Begin Alembic Export***")
print("Reason: " + error_message)
print("Contact the developers if you think that this is an error.")
return
exporter_library = None
exporter_library_error = None
try:
exporter_library = ctypes.cdll.LoadLibrary(exporter_library_filepath)
except Exception as e:
exporter_library_error = str(e.__class__.__name__) + " - " + str(e)
if exporter_library is None:
errmsg = "Unable to load Alembic export engine library: <" + exporter_library_filepath + ">\n"
if exporter_library_error is not None:
errmsg += "Reason: " + exporter_library_error
print("\n***ERROR: Unabled to Begin Alembic Export***")
print(errmsg)
print("Contact the developers if you think that this is an error.")
return
exporter_library.alembic_io_flip_fluids_cache_to_alembic.argtypes = [ctypes.c_char_p]
exporter_library.alembic_io_flip_fluids_cache_to_alembic(b_json_string)
print("Alembic export of cache <" + input_cache_directory + "> has been written to: <" + output_alembic_filepath + ">")
flip_fluids_alembic_export()
@@ -1,3 +1,19 @@
# 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 bpy, sys, os, threading, time, subprocess, queue
argv = sys.argv
@@ -1,3 +1,19 @@
# 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 bpy, sys, os, pathlib, threading, time, subprocess, queue
argv = sys.argv
@@ -1,3 +1,19 @@
# 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 bpy, sys, os, platform, subprocess
argv = sys.argv
@@ -1,3 +1,19 @@
# 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 bpy, sys, os, platform, subprocess
argv = sys.argv
@@ -1,3 +1,19 @@
# 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 bpy, os, json, time
def play_sound(json_audio_filepath, block=False):
@@ -1,3 +1,19 @@
# 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 bpy, os, json, time
def play_sound(json_audio_filepath, block=False):
@@ -1,3 +1,19 @@
# 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 bpy, sys, os, threading, time, subprocess, pathlib
from collections import namedtuple
@@ -1 +1 @@
Darwin 20.6.0 /Library/Developer/CommandLineTools/usr/bin/c++ AppleClang 12.0.5.12050022 2025-07-16 18:32:05 %z
Darwin 20.6.0 /Library/Developer/CommandLineTools/usr/bin/c++ AppleClang 12.0.5.12050022 2025-11-13 09:53:38 %z
@@ -1 +1 @@
Linux 4.4.0-210-generic /usr/bin/c++ GNU 9.4.0 1 2025-07-16 18:32:00 %z
Linux 4.4.0-210-generic /usr/bin/c++ GNU 9.4.0 1 2025-11-13 09:53:35 %z
@@ -1 +1 @@
Windows 6.2.9200 C:/dev/mingw64/bin/c++.exe GNU 15.0.0 1 2025-07-16 18:32:00 -0700
Windows 6.2.9200 C:/dev/mingw64/bin/c++.exe GNU 15.0.0 1 2025-11-13 09:53:34 -0800
@@ -274,3 +274,14 @@ preferences_menu_view_modes = (
('PREFERENCES_MENU_VIEW_PRESETS', "Presets Installation", "Install the asset browser preset library"),
('PREFERENCES_MENU_VIEW_SUPPORT', "Help & Support", "Info and links for help and support"),
)
"""
alembic_export_engines = (
('ALEMBIC_EXPORT_ENGINE_FLIP_FLUIDS', "FLIP Fluids", "Export using the custom FLIP Fluids Alembic Exporter"),
('ALEMBIC_EXPORT_ENGINE_BLENDER', "Blender", "Export using Blender's built-in Alembic Exporter")
)
"""
alembic_export_engines = (
('ALEMBIC_EXPORT_ENGINE_BLENDER', "Blender", "Export using Blender's built-in Alembic Exporter"),
)
@@ -40,27 +40,16 @@ class FLIPFLUID_PT_DomainTypeAdvancedPanel(bpy.types.Panel):
aprops = obj.flip_fluid.domain.advanced
wprops = obj.flip_fluid.domain.world
#
# Frame Substeps Panel
#
box = self.layout.box()
column = box.column(align=True)
split = vcu.ui_split(column, factor=0.45)
column_left = split.column(align=True)
column_right = split.column(align=True)
header, body = box.panel("frame_substeps_settings", default_closed=False)
row = column_left.row(align=True)
row.prop(aprops, "frame_substeps_expanded",
icon="TRIA_DOWN" if aprops.frame_substeps_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row = header.row(align=True)
row.label(text="Frame Substeps:")
if not aprops.frame_substeps_expanded:
row = column_right.row(align=True)
row.prop(aprops.min_max_time_steps_per_frame, "value_min", text="Min")
row.prop(aprops.min_max_time_steps_per_frame, "value_max", text="Max")
if aprops.frame_substeps_expanded:
column = box.column(align=True)
if body:
column = body.column(align=True)
if wprops.enable_surface_tension and aprops.min_max_time_steps_per_frame.value_max < wprops.minimum_surface_tension_substeps:
row = column.row(align=True)
row.alert = True
@@ -73,77 +62,66 @@ class FLIPFLUID_PT_DomainTypeAdvancedPanel(bpy.types.Panel):
column.prop(aprops, "CFL_condition_number")
column.prop(aprops, "enable_adaptive_obstacle_time_stepping")
column.prop(aprops, "enable_adaptive_force_field_time_stepping")
else:
row = row.row(align=True)
row.alignment = 'RIGHT'
row.prop(aprops.min_max_time_steps_per_frame, "value_min", text="Min")
row.prop(aprops.min_max_time_steps_per_frame, "value_max", text="Max")
#
# Simulation Method Panel
#
box = self.layout.box()
column = box.column(align=True)
split = vcu.ui_split(column, factor=0.5)
column_left = split.column(align=True)
column_right = split.column(align=True)
header, body = box.panel("simulation_method_settings", default_closed=False)
row = column_left.row(align=True)
row.prop(aprops, "simulation_method_expanded",
icon="TRIA_DOWN" if aprops.simulation_method_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row = header.row(align=True)
row.label(text="Simulation Method:")
if not aprops.simulation_method_expanded:
row = column_right.row(align=True)
row.prop(aprops, "velocity_transfer_method", expand=True)
if aprops.simulation_method_expanded:
column = box.column(align=True)
if body:
column = body.column(align=True)
row = column.row(align=True)
row.prop(aprops, "velocity_transfer_method", expand=True)
if aprops.velocity_transfer_method == 'VELOCITY_TRANSFER_METHOD_FLIP':
column.prop(aprops, "PICFLIP_ratio", slider=True)
else:
column.label(text="")
else:
row = row.row(align=True)
row.alignment = 'RIGHT'
row.prop(aprops, "velocity_transfer_method", expand=True)
#
# Simulation and Particle Stability Panel
#
box = self.layout.box()
row = box.row(align=True)
row.prop(aprops, "simulation_stability_expanded",
icon="TRIA_DOWN" if aprops.simulation_stability_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
header, body = box.panel("simulation_and_particle_stability_settings", default_closed=True)
row = header.row(align=True)
row.label(text="Simulation and Particle Stability:")
if aprops.simulation_stability_expanded:
column = box.column()
if body:
column = body.column()
row = column.row(align=True)
row.prop(aprops, "particle_jitter_factor", slider=True)
row.prop(aprops, "jitter_surface_particles")
column.prop(aprops, "enable_extreme_velocity_removal")
column.separator()
column = box.column(align=True)
column = body.column(align=True)
column.prop(aprops, "pressure_solver_max_iterations")
column.prop(aprops, "viscosity_solver_max_iterations")
box = self.layout.box()
row = box.row(align=True)
row.prop(aprops, "multithreading_expanded",
icon="TRIA_DOWN" if aprops.multithreading_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Multithreading and Performance:")
if not aprops.multithreading_expanded:
info_text = ""
if aprops.threading_mode == 'THREADING_MODE_AUTO_DETECT':
info_text = "Auto-detect " + str(aprops.num_threads_auto_detect) + " threads"
elif aprops.threading_mode == 'THREADING_MODE_FIXED':
info_text = "Fixed " + str(aprops.num_threads_fixed) + " threads"
else:
row = row.row(align=True)
row.alignment = 'RIGHT'
row.label(text=info_text)
row.prop(aprops, "jitter_surface_particles")
if aprops.multithreading_expanded:
column = box.column()
#
# Multithreading and Performance Panel
#
box = self.layout.box()
header, body = box.panel("multithreading_and_performance_settings", default_closed=False)
row = header.row(align=True)
row.label(text="Multithreading and Performance:")
if body:
column = body.column()
split = column.split(align=True)
column_left = split.column(align=True)
@@ -156,31 +134,29 @@ class FLIPFLUID_PT_DomainTypeAdvancedPanel(bpy.types.Panel):
elif aprops.threading_mode == 'THREADING_MODE_FIXED':
row.prop(aprops, "num_threads_fixed")
column = box.column()
column = body.column()
column.prop(aprops, "enable_fracture_optimization")
# Performance and optimization settings are hidden from the UI.
# These should always be enabled for performance.
"""
column = self.layout.column(align=True)
column.separator()
column.label(text="Performance and Optimization:")
column.prop(aprops, "enable_asynchronous_meshing")
column.prop(aprops, "precompute_static_obstacles")
column.prop(aprops, "reserve_temporary_grids")
"""
else:
info_text = ""
if aprops.threading_mode == 'THREADING_MODE_AUTO_DETECT':
info_text = "Auto-detect " + str(aprops.num_threads_auto_detect) + " threads"
elif aprops.threading_mode == 'THREADING_MODE_FIXED':
info_text = "Fixed " + str(aprops.num_threads_fixed) + " threads"
row = row.row(align=True)
row.alignment = 'RIGHT'
row.label(text=info_text)
#
# Warnings and Errors Panel
#
box = self.layout.box()
row = box.row(align=True)
row.prop(aprops, "warnings_and_errors_expanded",
icon="TRIA_DOWN" if aprops.warnings_and_errors_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Warnings and Errors:")
header, body = box.panel("warnings_and_errors_settings", default_closed=True)
if aprops.warnings_and_errors_expanded:
column = box.column(align=True)
row = header.row(align=True)
row.label(text="Warnings and Errors:")
if body:
column = body.column(align=True)
column.prop(aprops, "disable_changing_topology_warning")
@@ -59,21 +59,16 @@ class FLIPFLUID_PT_DomainTypeCachePanel(bpy.types.Panel):
dprops = domain_object.flip_fluid.domain
cprops = dprops.cache
#
# Cache Directory Panel
#
box = self.layout.box()
row = box.row(align=True)
row.prop(cprops, "cache_directory_expanded",
icon="TRIA_DOWN" if cprops.cache_directory_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
header, body = box.panel("cache_directory", default_closed=False)
row = header.row(align=True)
row.label(text="Cache Directory:")
if not cprops.cache_directory_expanded:
row = row.row()
row.prop(cprops, "cache_directory")
if cprops.cache_directory_expanded:
column = box.column(align=True)
if body:
column = body.column(align=True)
subcolumn = column.column(align=True)
subcolumn.enabled = not dprops.bake.is_simulation_running
row = subcolumn.row(align=True)
@@ -85,18 +80,22 @@ class FLIPFLUID_PT_DomainTypeCachePanel(bpy.types.Panel):
row.operator("flip_fluid_operators.relative_cache_directory")
row.operator("flip_fluid_operators.absolute_cache_directory")
row.operator("flip_fluid_operators.match_filename_cache_directory")
else:
row = row.row(align=True)
row.prop(cprops, "cache_directory")
row.operator("flip_fluid_operators.increase_decrease_cache_directory", text="", icon="REMOVE").increment_mode = "DECREASE"
row.operator("flip_fluid_operators.increase_decrease_cache_directory", text="", icon="ADD").increment_mode = "INCREASE"
#
# Link Existing Exported Geometry Panel
#
box = self.layout.box()
row = box.row(align=True)
row.prop(cprops, "link_exported_geometry_expanded",
icon="TRIA_DOWN" if cprops.link_exported_geometry_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Link existing exported geometry:")
header, body = box.panel("link_existing_exported_geometry", default_closed=True)
if cprops.link_exported_geometry_expanded:
column = box.column(align=True)
row = header.row(align=True)
row.label(text="Link Existing Exported Geometry:")
if body:
column = body.column(align=True)
subcolumn = column.column(align=True)
subcolumn.enabled = not dprops.bake.is_simulation_running
subcolumn.prop(cprops, "linked_geometry_directory")
@@ -106,56 +105,38 @@ class FLIPFLUID_PT_DomainTypeCachePanel(bpy.types.Panel):
column = column.column(align=True)
column.operator("flip_fluid_operators.clear_linked_geometry_directory")
column.separator()
else:
row = row.row(align=True)
row.prop(cprops, "linked_geometry_directory")
#
# Cache Operators Panel
#
if dprops.stats.is_cache_info_available:
free_text = "Free (" + format_bytes(self, dprops.stats.cache_bytes.get()) + ")"
else:
free_text = "Free"
box = self.layout.box()
row = box.row(align=True)
row.prop(cprops, "cache_operators_expanded",
icon="TRIA_DOWN" if cprops.cache_operators_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
header, body = box.panel("cache_operators", default_closed=True)
row = header.row(align=True)
row.label(text="Cache Operators:")
if not cprops.cache_operators_expanded:
if dprops.stats.is_cache_info_available:
free_text = "Free (" + format_bytes(self, dprops.stats.cache_bytes.get()) + ")"
else:
free_text = "Free"
row.operator("flip_fluid_operators.free_cache", text=free_text)
if cprops.cache_operators_expanded:
column = box.column(align=True)
# The move, rename, and copy cache operations should not be performed
# in Blender and are removed from the UI. There is a potential for Blender
# to crash, which could lead to loss of data. It is best to perform these
# operations through the OS filesystem which is cabable of handling failures.
"""
row = column.row(align=True)
row.operator("flip_fluid_operators.move_cache", text="Move")
row.prop(cprops, "move_cache_directory")
row = column.row(align=True)
row.operator("flip_fluid_operators.rename_cache", text="Rename")
row.prop(cprops, "rename_cache_directory")
row = column.row(align=True)
row.operator("flip_fluid_operators.copy_cache", text="Copy")
row.prop(cprops, "copy_cache_directory")
"""
if dprops.stats.is_cache_info_available:
free_text = "Free (" + format_bytes(self, dprops.stats.cache_bytes.get()) + ")"
else:
free_text = "Free"
if body:
column = body.column(align=True)
split = column.split(align=True)
column_left = split.column(align=True)
column_right = split.column(align=True)
column_left.operator("flip_fluid_operators.free_cache", text=free_text)
column_right.prop(cprops, "clear_cache_directory_logs", text="Free log files")
column_right.prop(cprops, "clear_cache_directory_export", text="Free export files")
else:
if dprops.stats.is_cache_info_available:
free_text = "Free (" + format_bytes(self, dprops.stats.cache_bytes.get()) + ")"
else:
free_text = "Free"
row.operator("flip_fluid_operators.free_cache", text=free_text)
def register():
@@ -39,19 +39,18 @@ class FLIPFLUID_PT_DomainTypeDebugPanel(bpy.types.Panel):
obj = vcu.get_active_object(context)
gprops = obj.flip_fluid.domain.debug
#
# Grid Visualization Panel
#
box = self.layout.box()
row = box.row(align=True)
row.prop(gprops, "grid_display_settings_expanded",
icon="TRIA_DOWN" if gprops.grid_display_settings_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
if not gprops.grid_display_settings_expanded:
row.prop(gprops, "display_simulation_grid", text="")
row.label(text="Grid Visualization:")
header, body = box.panel("grid_visualization_settings", default_closed=False)
if gprops.grid_display_settings_expanded:
split = vcu.ui_split(box, align=True, factor=0.3)
row = header.row(align=True)
if not body:
row.prop(gprops, "display_simulation_grid", text="")
row.label(text="Grid Visualization:")
if body:
split = vcu.ui_split(body, align=True, factor=0.3)
column = split.column(align=True)
column.prop(gprops, "display_simulation_grid", text="Display Grid")
@@ -63,7 +62,7 @@ class FLIPFLUID_PT_DomainTypeDebugPanel(bpy.types.Panel):
column = split.column(align=True)
column.prop(gprops, "grid_display_scale", text="Draw Scale")
split = vcu.ui_split(box, align=True, factor=0.3)
split = vcu.ui_split(body, align=True, factor=0.3)
column = split.column(align=True)
column.enabled = gprops.display_simulation_grid
column.label(text="Enabled Grids:")
@@ -81,7 +80,7 @@ class FLIPFLUID_PT_DomainTypeDebugPanel(bpy.types.Panel):
row.prop(gprops, "debug_grid_offsets", text="", slider=True)
column.prop(gprops, "snap_offsets_to_grid")
column = box.column(align=True)
column = body.column(align=True)
split = vcu.ui_split(column, align=True, factor=0.3)
column = split.column(align=True)
column.prop(gprops, "display_domain_bounds")
@@ -90,14 +89,14 @@ class FLIPFLUID_PT_DomainTypeDebugPanel(bpy.types.Panel):
column.enabled = gprops.display_simulation_grid or gprops.display_domain_bounds
column.prop(gprops, "domain_bounds_color", text="")
#
# Fluid Particle Debugging Panel
#
box = self.layout.box()
row = box.row(align=True)
row.prop(gprops, "particle_debug_settings_expanded",
icon="TRIA_DOWN" if gprops.particle_debug_settings_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
if not gprops.particle_debug_settings_expanded:
header, body = box.panel("fluid_particle_debugging_settings", default_closed=True)
row = header.row(align=True)
if not body:
row.prop(gprops, "enable_fluid_particle_debug_output", text="")
row.label(text="Fluid Particle Debugging:")
@@ -109,10 +108,9 @@ class FLIPFLUID_PT_DomainTypeDebugPanel(bpy.types.Panel):
emboss=False
)
if gprops.particle_debug_settings_expanded:
box.prop(gprops, "enable_fluid_particle_debug_output")
column = box.column(align=True)
if body:
body.prop(gprops, "enable_fluid_particle_debug_output")
column = body.column(align=True)
column.enabled = gprops.enable_fluid_particle_debug_output
column.label(text="Particle Display Settings:")
row = column.row(align=True)
@@ -124,7 +122,7 @@ class FLIPFLUID_PT_DomainTypeDebugPanel(bpy.types.Panel):
row = column.row(align=True)
row.prop(gprops, "fluid_particle_gradient_mode", expand=True)
column = box.column()
column = body.column()
column.enabled = gprops.enable_fluid_particle_debug_output
split = vcu.ui_split(column, factor=0.33)
column = split.column()
@@ -134,14 +132,14 @@ class FLIPFLUID_PT_DomainTypeDebugPanel(bpy.types.Panel):
column.prop(gprops, "particle_size", text="")
column.prop_search(gprops, "particle_draw_aabb", bpy.data, "objects", text="")
#
# Force Field Debugging Panel
#
box = self.layout.box()
row = box.row(align=True)
row.prop(gprops, "force_field_debug_settings_expanded",
icon="TRIA_DOWN" if gprops.force_field_debug_settings_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
if not gprops.force_field_debug_settings_expanded:
header, body = box.panel("force_field_debugging_settings", default_closed=True)
row = header.row(align=True)
if not body:
row.prop(gprops, "export_force_field", text="")
row.label(text="Force Field Debugging:")
@@ -153,9 +151,9 @@ class FLIPFLUID_PT_DomainTypeDebugPanel(bpy.types.Panel):
emboss=False
)
if gprops.force_field_debug_settings_expanded:
box.prop(gprops, "export_force_field")
column = box.column(align=True)
if body:
body.prop(gprops, "export_force_field")
column = body.column(align=True)
column.enabled = gprops.export_force_field
column.label(text="Force Field Display Settings:")
@@ -168,7 +166,7 @@ class FLIPFLUID_PT_DomainTypeDebugPanel(bpy.types.Panel):
row = column.row(align=True)
row.prop(gprops, "force_field_gradient_mode", expand=True)
column = box.column()
column = body.column()
column.enabled = gprops.export_force_field
split = vcu.ui_split(column, factor=0.33)
column = split.column()
@@ -179,17 +177,24 @@ class FLIPFLUID_PT_DomainTypeDebugPanel(bpy.types.Panel):
column.prop(gprops, "force_field_display_amount", text="")
column.prop(gprops, "force_field_line_size", text="")
#
# Obstacle Debugging Panel
#
box = self.layout.box()
row = box.row(align=True)
row.prop(gprops, "export_internal_obstacle_mesh")
next_row = row.row()
next_row.alignment = 'RIGHT'
next_row.prop(gprops, "internal_obstacle_mesh_visibility",
text="",
icon=vcu.get_hide_off_icon() if gprops.internal_obstacle_mesh_visibility else vcu.get_hide_on_icon(),
emboss=False
)
text="",
icon=vcu.get_hide_off_icon() if gprops.internal_obstacle_mesh_visibility else vcu.get_hide_on_icon(),
emboss=False
)
#
# Misc Debugging Panel
#
box = self.layout.box()
column = box.column(align=True)
column.prop(gprops, "display_render_passes_console_output")
@@ -25,16 +25,14 @@ def draw_simulation_display_settings(self, context):
rprops = domain_object.flip_fluid.domain.render
scene_props = context.scene.flip_fluid
#
# Simulation Visibility Panel
#
box = self.layout.box()
column = box.column()
row = column.row(align=True)
row.prop(rprops, "simulation_display_settings_expanded",
icon="TRIA_DOWN" if rprops.simulation_display_settings_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
header, body = box.panel("simulation_display_settings", default_closed=True)
row = header.row(align=True)
row.label(text="Simulation Visibility:")
if not scene_props.show_viewport or not scene_props.show_render:
visibility_text = ""
@@ -55,15 +53,14 @@ def draw_simulation_display_settings(self, context):
row.alignment = 'RIGHT'
row.label(text="Visibility Enabled", icon="CHECKMARK")
if not rprops.simulation_display_settings_expanded:
return
if body:
column = body.column()
split = vcu.ui_split(column)
column_left = split.column()
column_left.prop(scene_props, "show_render", text="Show In Render", icon="RESTRICT_RENDER_OFF")
split = vcu.ui_split(column)
column_left = split.column()
column_left.prop(scene_props, "show_render", text="Show In Render", icon="RESTRICT_RENDER_OFF")
column_right = split.column()
column_right.prop(scene_props, "show_viewport", text="Show In Viewport", icon="RESTRICT_VIEW_OFF")
column_right = split.column()
column_right.prop(scene_props, "show_viewport", text="Show In Viewport", icon="RESTRICT_VIEW_OFF")
def draw_surface_display_settings(self, context, menu_expand_prop_group=None):
@@ -71,18 +68,28 @@ def draw_surface_display_settings(self, context, menu_expand_prop_group=None):
rprops = domain_object.flip_fluid.domain.render
mprops = domain_object.flip_fluid.domain.materials
#
# Surface Display and Render Panel
#
box = self.layout.box()
column = box.column()
header, body = box.panel("surface_display_settings", default_closed=False)
row = column.row(align=True)
row.prop(menu_expand_prop_group, "surface_display_settings_expanded",
icon="TRIA_DOWN" if getattr(menu_expand_prop_group, "surface_display_settings_expanded") else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row = header.row(align=True)
row.label(text="Surface Display and Render:")
if body:
column = body.column()
split = vcu.ui_split(column, factor=0.5)
column_left = split.column()
column_left.label(text="Render Display Mode:")
column_left.prop(rprops, "render_display", expand=True)
if not getattr(menu_expand_prop_group, "surface_display_settings_expanded"):
column_right = split.column()
column_right.label(text="Viewport Display Mode:")
column_right.prop(rprops, "viewport_display", expand=True)
column_left.label(text="Surface Material:")
column_right.prop(mprops, "surface_material", text="")
else:
info_text = ""
if rprops.render_display == 'DISPLAY_FINAL':
info_text += "Render Final"
@@ -100,19 +107,6 @@ def draw_surface_display_settings(self, context, menu_expand_prop_group=None):
row = row.row(align=True)
row.alignment='RIGHT'
row.label(text=info_text)
return
split = vcu.ui_split(column, factor=0.5)
column_left = split.column()
column_left.label(text="Render Display Mode:")
column_left.prop(rprops, "render_display", expand=True)
column_right = split.column()
column_right.label(text="Viewport Display Mode:")
column_right.prop(rprops, "viewport_display", expand=True)
column_left.label(text="Surface Material:")
column_right.prop(mprops, "surface_material", text="")
def draw_fluid_particle_display_settings(self, context, menu_expand_prop_group=None):
@@ -122,61 +116,25 @@ def draw_fluid_particle_display_settings(self, context, menu_expand_prop_group=N
mprops = domain_object.flip_fluid.domain.materials
is_fluid_particles_enabled = domain_object.flip_fluid.domain.particles.enable_fluid_particle_output
#
# Fluid Particle Display and Render Panel
#
box = self.layout.box()
column = box.column()
header, body = box.panel("fluid_particle_display_settings", default_closed=True)
if is_fluid_particles_enabled:
row = column.row(align=True)
row.prop(menu_expand_prop_group, "fluid_particle_display_settings_expanded",
icon="TRIA_DOWN" if getattr(menu_expand_prop_group, "fluid_particle_display_settings_expanded") else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Fluid Particle Display and Render:")
else:
split = column.split()
left_column = split.column()
row = left_column.row(align=True)
row.prop(menu_expand_prop_group, "fluid_particle_display_settings_expanded",
icon="TRIA_DOWN" if getattr(menu_expand_prop_group, "fluid_particle_display_settings_expanded") else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Fluid Particle Display and Render:")
right_column = split.column()
row = right_column.row()
row = header.row(align=True)
row.label(text="Fluid Particle Display and Render:")
if not is_fluid_particles_enabled:
row = row.row()
row.alignment = 'RIGHT'
c = row.row(align=True)
c.alignment = 'RIGHT'
c.enabled = False
c.label(text="Enable in 'Particles' panel")
row.operator("flip_fluid_operators.display_enable_fluid_particles_tooltip",
text="", icon="QUESTION", emboss=False)
row.operator("flip_fluid_operators.display_enable_fluid_particles_tooltip", text="", icon="QUESTION", emboss=False)
if not getattr(menu_expand_prop_group, "fluid_particle_display_settings_expanded"):
if is_fluid_particles_enabled:
info_text = ""
if rprops.fluid_particle_render_display == 'DISPLAY_FINAL':
info_text += "Render Final"
elif rprops.fluid_particle_render_display == 'DISPLAY_PREVIEW':
info_text += "Render Preview"
elif rprops.fluid_particle_render_display == 'DISPLAY_NONE':
info_text += "Render None"
info_text += " / "
if rprops.fluid_particle_viewport_display == 'DISPLAY_FINAL':
info_text += "View Final"
elif rprops.fluid_particle_viewport_display == 'DISPLAY_PREVIEW':
info_text += "View Preview"
elif rprops.fluid_particle_viewport_display == 'DISPLAY_NONE':
info_text += "View None"
row = row.row(align=True)
row.alignment='RIGHT'
row.label(text=info_text)
return
if getattr(menu_expand_prop_group, "fluid_particle_display_settings_expanded"):
subbox = box.box()
if body:
subbox = body.box()
column = subbox.column(align=True)
column.enabled = is_fluid_particles_enabled
split = vcu.ui_split(column, factor=0.5)
@@ -229,6 +187,25 @@ def draw_fluid_particle_display_settings(self, context, menu_expand_prop_group=N
column_right = split.column()
column_left.label(text="Fluid Particle Material:")
column_right.prop(mprops, "fluid_particles_material", text="")
else:
if is_fluid_particles_enabled:
info_text = ""
if rprops.fluid_particle_render_display == 'DISPLAY_FINAL':
info_text += "Render Final"
elif rprops.fluid_particle_render_display == 'DISPLAY_PREVIEW':
info_text += "Render Preview"
elif rprops.fluid_particle_render_display == 'DISPLAY_NONE':
info_text += "Render None"
info_text += " / "
if rprops.fluid_particle_viewport_display == 'DISPLAY_FINAL':
info_text += "View Final"
elif rprops.fluid_particle_viewport_display == 'DISPLAY_PREVIEW':
info_text += "View Preview"
elif rprops.fluid_particle_viewport_display == 'DISPLAY_NONE':
info_text += "View None"
row = row.row(align=True)
row.alignment='RIGHT'
row.label(text=info_text)
def get_motion_blur_geometry_node_modifier(bl_object):
@@ -244,7 +221,7 @@ def draw_whitewater_particles_motion_blur_geometry_node_properties(ui_row, bl_mo
ui_row.alert = True
ui_row.operator(
"flip_fluid_operators.helper_initialize_cache_objects",
text="Initialize Geometry Nodes - Missing FF_GeometryNodesWhitewater modifier",
text="Click To Initialize Geometry Nodes - Missing FF_GeometryNodesWhitewater modifier",
icon="ERROR"
).cache_object_type = 'CACHE_OBJECT_TYPE_WHITEWATER_PARTICLES'
return
@@ -256,8 +233,6 @@ def draw_whitewater_particles_motion_blur_geometry_node_properties(ui_row, bl_mo
ui_row.prop(bl_mod, '["Input_4"]', text="Blur Scale")
if "Input_8" in bl_mod:
ui_row.prop(bl_mod, '["Input_8"]', text="Motion Blur")
if "Input_9" in bl_mod:
ui_row.prop(bl_mod, '["Input_9"]', text="Point Cloud")
def draw_fluid_particles_motion_blur_geometry_node_properties(ui_row, bl_mod):
@@ -265,7 +240,7 @@ def draw_fluid_particles_motion_blur_geometry_node_properties(ui_row, bl_mod):
ui_row.alert = True
ui_row.operator(
"flip_fluid_operators.helper_initialize_cache_objects",
text="Initialize Geometry Nodes - Missing FF_GeometryNodesFluidParticles modifier",
text="Click To Initialize Geometry Nodes - Missing FF_GeometryNodesFluidParticles modifier",
icon="ERROR"
).cache_object_type = 'CACHE_OBJECT_TYPE_FLUID_PARTICLES'
return
@@ -277,8 +252,6 @@ def draw_fluid_particles_motion_blur_geometry_node_properties(ui_row, bl_mod):
ui_row.prop(bl_mod, '["Input_4"]', text="Blur Scale")
if "Input_8" in bl_mod:
ui_row.prop(bl_mod, '["Input_8"]', text="Motion Blur")
if "Input_9" in bl_mod:
ui_row.prop(bl_mod, '["Input_9"]', text="Point Cloud")
def draw_whitewater_display_settings(self, context, menu_expand_prop_group=None):
@@ -287,61 +260,25 @@ def draw_whitewater_display_settings(self, context, menu_expand_prop_group=None)
rprops = dprops.render
is_whitewater_enabled = dprops.whitewater.enable_whitewater_simulation
master_box = self.layout.box()
column = master_box.column()
#
# Whitewater Display and Render Panel
#
box = self.layout.box()
header, body = box.panel("whitewater_display_settings", default_closed=True)
if is_whitewater_enabled:
row = column.row(align=True)
row.prop(menu_expand_prop_group, "whitewater_display_settings_expanded",
icon="TRIA_DOWN" if getattr(menu_expand_prop_group, "whitewater_display_settings_expanded") else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Whitewater Display and Render:")
else:
split = column.split()
left_column = split.column()
row = left_column.row(align=True)
row.prop(menu_expand_prop_group, "whitewater_display_settings_expanded",
icon="TRIA_DOWN" if getattr(menu_expand_prop_group, "whitewater_display_settings_expanded") else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Whitewater Display and Render:")
right_column = split.column()
row = right_column.row()
row = header.row(align=True)
row.label(text="Whitewater Display and Render:")
if not is_whitewater_enabled:
row = row.row()
row.alignment = 'RIGHT'
c = row.row(align=True)
c.alignment = 'RIGHT'
c.enabled = False
c.label(text="Enable in 'Whitewater' panel")
row.operator("flip_fluid_operators.display_enable_whitewater_tooltip",
text="", icon="QUESTION", emboss=False)
row.operator("flip_fluid_operators.display_enable_whitewater_tooltip", text="", icon="QUESTION", emboss=False)
if not getattr(menu_expand_prop_group, "whitewater_display_settings_expanded"):
if is_whitewater_enabled:
info_text = ""
if rprops.whitewater_render_display == 'DISPLAY_FINAL':
info_text += "Render Final"
elif rprops.whitewater_render_display == 'DISPLAY_PREVIEW':
info_text += "Render Preview"
elif rprops.whitewater_render_display == 'DISPLAY_NONE':
info_text += "Render None"
info_text += " / "
if rprops.whitewater_viewport_display == 'DISPLAY_FINAL':
info_text += "View Final"
elif rprops.whitewater_viewport_display == 'DISPLAY_PREVIEW':
info_text += "View Preview"
elif rprops.whitewater_viewport_display == 'DISPLAY_NONE':
info_text += "View None"
row = row.row(align=True)
row.alignment='RIGHT'
row.label(text=info_text)
return
if getattr(menu_expand_prop_group, "whitewater_display_settings_expanded"):
box = master_box.box()
if body:
box = body.box()
box.enabled = is_whitewater_enabled
column = box.column(align=True)
@@ -354,21 +291,7 @@ def draw_whitewater_display_settings(self, context, menu_expand_prop_group=None)
column.label(text="Viewport Display Mode:")
column.prop(rprops, "whitewater_viewport_display", expand=True)
# Whitewater motion blur rendering is currently too resource intensive
# for Blender Cycles
"""
column = box.column()
column.label(text="Motion Blur:")
split = vcu.ui_split(column, factor=0.5)
column_left = split.column()
column_left.prop(rprops, "render_whitewater_motion_blur")
column_right = split.column()
column_right.prop(rprops, "whitewater_motion_blur_scale")
"""
box = master_box.box()
box = body.box()
box.enabled = is_whitewater_enabled
column = box.column(align=True)
@@ -387,7 +310,7 @@ def draw_whitewater_display_settings(self, context, menu_expand_prop_group=None)
column.prop(rprops, "viewport_spray_pct", slider=True)
column.prop(rprops, "viewport_dust_pct", slider=True)
box = master_box.box()
box = body.box()
box.enabled = is_whitewater_enabled
column = box.column(align=True)
@@ -416,7 +339,7 @@ def draw_whitewater_display_settings(self, context, menu_expand_prop_group=None)
else:
row.label(text="Enable Whitewater feature to view full particle settings", icon='INFO')
box = master_box.box()
box = body.box()
box.enabled = is_whitewater_enabled
mprops = dprops.materials
@@ -426,6 +349,25 @@ def draw_whitewater_display_settings(self, context, menu_expand_prop_group=None)
column.prop(mprops, "whitewater_bubble_material", text="Bubble")
column.prop(mprops, "whitewater_spray_material", text="Spray")
column.prop(mprops, "whitewater_dust_material", text="Dust")
else:
if is_whitewater_enabled:
info_text = ""
if rprops.whitewater_render_display == 'DISPLAY_FINAL':
info_text += "Render Final"
elif rprops.whitewater_render_display == 'DISPLAY_PREVIEW':
info_text += "Render Preview"
elif rprops.whitewater_render_display == 'DISPLAY_NONE':
info_text += "Render None"
info_text += " / "
if rprops.whitewater_viewport_display == 'DISPLAY_FINAL':
info_text += "View Final"
elif rprops.whitewater_viewport_display == 'DISPLAY_PREVIEW':
info_text += "View Preview"
elif rprops.whitewater_viewport_display == 'DISPLAY_NONE':
info_text += "View None"
row = row.row(align=True)
row.alignment='RIGHT'
row.label(text=info_text)
class FLIPFLUID_PT_DomainTypeDisplayPanel(bpy.types.Panel):
@@ -36,43 +36,29 @@ def _draw_geometry_attributes_menu(self, context):
#
# Geometry Attributes
#
#
box = self.layout.box()
row = box.row(align=True)
row.prop(pprops, "geometry_attributes_expanded",
icon="TRIA_DOWN" if pprops.geometry_attributes_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
header, body = box.panel("fluid_particle_geometry_attributes", default_closed=True)
row = header.row(align=True)
row.label(text="Fluid Particle Attributes:")
if pprops.geometry_attributes_expanded:
if not vcu.is_blender_31():
column = box.column(align=True)
column.enabled = False
column.label(text="Geometry attribute features for fluid particles are only available in", icon='ERROR')
column.label(text="Blender 3.1 or later", icon='ERROR')
return
if body:
#
# Velocity Attributes
#
subbox = box.box()
row = subbox.row(align=True)
row.prop(pprops, "velocity_attributes_expanded",
icon="TRIA_DOWN" if pprops.velocity_attributes_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Velocity Based Attributes:")
box = body.box()
header_velocity, body_velocity = box.panel("fluid_particle_velocity_attributes", default_closed=True)
if pprops.velocity_attributes_expanded:
column = subbox.column(align=True)
row_velocity = header_velocity.row(align=True)
row_velocity.label(text="Velocity Based Attributes:")
if body_velocity:
column = body_velocity.column(align=True)
column.prop(pprops, "enable_fluid_particle_velocity_vector_attribute", text="Velocity Attributes")
column.prop(pprops, "enable_fluid_particle_speed_attribute", text="Speed Attributes")
column.prop(pprops, "enable_fluid_particle_vorticity_vector_attribute", text="Vorticity Attributes")
column.operator("flip_fluid_operators.helper_initialize_motion_blur")
else:
row = row.row(align=True)
row = row_velocity.row(align=True)
row.alignment = 'RIGHT'
row.prop(pprops, "enable_fluid_particle_velocity_vector_attribute", text="Velocity")
row.prop(pprops, "enable_fluid_particle_speed_attribute", text="Speed")
@@ -81,23 +67,19 @@ def _draw_geometry_attributes_menu(self, context):
#
# Color Attributes
#
subbox = box.box()
row = subbox.row(align=True)
row.prop(pprops, "color_attributes_expanded",
icon="TRIA_DOWN" if pprops.color_attributes_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Color and Mixing Attributes:")
box = body.box()
header_color, body_color = box.panel("fluid_particle_color_attributes", default_closed=True)
if pprops.color_attributes_expanded:
column = subbox.column(align=True)
row_color = header_color.row(align=True)
row_color.label(text="Color and Mixing Attributes:")
if body_color:
column = body_color.column(align=True)
split = column.split(align=True)
column_left = split.column(align=True)
column_right = split.column(align=True)
column_left.prop(pprops, "enable_fluid_particle_color_attribute", text="Color Attributes")
column = subbox.column(align=True)
column = body_color.column(align=True)
split = column.split(align=True)
column_left = split.column(align=True)
column_right = split.column(align=True)
@@ -106,7 +88,7 @@ def _draw_geometry_attributes_menu(self, context):
column_right.enabled = pprops.enable_fluid_particle_color_attribute and sprops.enable_color_attribute_mixing
column_right.prop(sprops, "color_attribute_mixing_rate", text="Mix Rate", slider=True)
column = subbox.column(align=True)
column = body_color.column(align=True)
column.enabled = pprops.enable_fluid_particle_color_attribute and sprops.enable_color_attribute_mixing
column.label(text="Mixing Mode:")
row = column.row(align=True)
@@ -129,10 +111,10 @@ def _draw_geometry_attributes_menu(self, context):
text="Open Preferences", icon="PREFERENCES"
).view_mode = 'PREFERENCES_MENU_VIEW_MIXBOX'
else:
row = row.row(align=True)
row = row_color.row(align=True)
row.alignment = 'RIGHT'
row.prop(pprops, "enable_fluid_particle_color_attribute", text="Color")
row = row.row(align=True)
row = row_color.row(align=True)
row.alignment = 'RIGHT'
row.enabled = pprops.enable_fluid_particle_color_attribute
row.prop(sprops, "enable_color_attribute_mixing", text="Mixing")
@@ -140,17 +122,13 @@ def _draw_geometry_attributes_menu(self, context):
#
# Other Attributes
#
subbox = box.box()
row = subbox.row(align=True)
row.prop(pprops, "other_attributes_expanded",
icon="TRIA_DOWN" if pprops.other_attributes_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Other Attributes:")
box = body.box()
header_other, body_other = box.panel("fluid_particle_other_attributes", default_closed=True)
if pprops.other_attributes_expanded:
column = subbox.column(align=True)
row_other = header_other.row(align=True)
row_other.label(text="Other Attributes:")
if body_other:
column = body_other.column(align=True)
column.prop(pprops, "enable_fluid_particle_age_attribute", text="Age Attributes")
row = column.row(align=True)
row.prop(pprops, "enable_fluid_particle_lifetime_attribute", text="Lifetime Attributes")
@@ -161,7 +139,7 @@ def _draw_geometry_attributes_menu(self, context):
row.prop(pprops, "enable_fluid_particle_uid_attribute", text="UID Attributes")
row.prop(pprops, "enable_fluid_particle_uid_attribute_reuse", text="Reuse UIDs")
else:
row = row.row(align=True)
row = row_other.row(align=True)
row.alignment = 'RIGHT'
row.prop(pprops, "enable_fluid_particle_age_attribute", text="Age")
row.prop(pprops, "enable_fluid_particle_lifetime_attribute", text="Life")
@@ -192,41 +170,18 @@ class FLIPFLUID_PT_DomainTypeFluidParticlesPanel(bpy.types.Panel):
dprops = obj.flip_fluid.domain
pprops = obj.flip_fluid.domain.particles
sprops = obj.flip_fluid.domain.surface
aprops = dprops.advanced
prefs = vcu.get_addon_preferences()
if not prefs.is_extra_features_enabled():
warn_box = self.layout.box()
warn_column = warn_box.column(align=True)
warn_column.enabled = True
warn_column.label(text=" This feature is affected by a current bug in Blender.", icon='ERROR')
warn_column.label(text=" The Extra Features option must be enabled in preferences")
warn_column.label(text=" to use this feature.")
warn_column.separator()
warn_column.prop(prefs, "enable_extra_features", text="Enable Extra Features in Preferences")
warn_column.separator()
warn_column.operator(
"wm.url_open",
text="Important Info and Limitations",
icon="WORLD"
).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Preferences-Menu-Settings#developer-tools"
return
#
# Fluid Particle Export Panel
#
box = self.layout.box()
row = box.row(align=True)
row.prop(pprops, "fluid_particles_expanded",
icon="TRIA_DOWN" if pprops.fluid_particles_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
header, body = box.panel("fluid_particles", default_closed=False)
row = header.row(align=True)
row.label(text="Fluid Particle Export:")
if not pprops.fluid_particles_expanded:
row = row.row(align=True)
row.alignment = 'RIGHT'
row.prop(pprops, "enable_fluid_particle_output")
if pprops.fluid_particles_expanded:
column = box.column(align=True)
if body:
column = body.column(align=True)
column.prop(pprops, "enable_fluid_particle_output")
subbox = column.box()
subbox.enabled = pprops.enable_fluid_particle_output
@@ -237,27 +192,28 @@ class FLIPFLUID_PT_DomainTypeFluidParticlesPanel(bpy.types.Panel):
subcolumn.prop(pprops, "enable_fluid_particle_interior_output")
subcolumn.separator()
subcolumn.prop(pprops, "fluid_particle_source_id_blacklist", text="Skip Particles With Source ID Value")
box = self.layout.box()
row = box.row(align=True)
row.prop(pprops, "fluid_particle_generation_expanded",
icon="TRIA_DOWN" if pprops.fluid_particle_generation_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Fluid Particle Generation:")
aprops = dprops.advanced
if not pprops.fluid_particle_generation_expanded:
else:
row = row.row(align=True)
row.alignment = 'RIGHT'
row.prop(aprops, "jitter_surface_particles")
row.prop(pprops, "enable_fluid_particle_output")
if pprops.fluid_particle_generation_expanded:
column = box.column()
#
# Fluid Particle Generation Panel
#
box = self.layout.box()
header, body = box.panel("fluid_particle_generation", default_closed=True)
row = header.row(align=True)
row.label(text="Fluid Particle Generation:")
if body:
column = body.column()
row = column.row(align=True)
row.prop(aprops, "particle_jitter_factor", slider=True)
row.prop(aprops, "jitter_surface_particles")
else:
row = row.row(align=True)
row.alignment = 'RIGHT'
row.prop(aprops, "jitter_surface_particles")
_draw_fluid_particle_display_settings(self, context)
_draw_geometry_attributes_menu(self, context)
@@ -112,211 +112,313 @@ def draw_bake_operator(self, context, box):
draw_bake_operator_UI_element(context, box)
def draw_more_bake_settings(self, context, box):
def draw_more_bake_settings(self, context, master_column):
obj = vcu.get_active_object(context)
dprops = obj.flip_fluid.domain
sprops = dprops.simulation
row = box.row(align=True)
row.prop(sprops, "more_bake_settings_expanded",
icon="TRIA_DOWN" if sprops.more_bake_settings_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="More Bake Settings")
#
# More Bake Settings Panel
#
box = master_column.box()
header, body = box.panel("more_bake_settings", default_closed=True)
if not sprops.more_bake_settings_expanded:
return
row = header.row(align=True)
row.label(text="More Bake Settings:")
subbox = box.box()
column = subbox.column(align=True)
column.label(text="Frame Range:")
row = column.row()
row.prop(sprops, "frame_range_mode", expand=True)
row = column.row(align=True)
if sprops.frame_range_mode == 'FRAME_RANGE_TIMELINE':
row_left = row.row(align=True)
row_right = row.row(align=True)
if dprops.bake.is_autosave_available:
row_left.enabled = False
row_left.prop(dprops.bake, "original_frame_start")
else:
row_left.prop(context.scene, "frame_start")
row_right.prop(context.scene, "frame_end")
else:
row_left = row.row(align=True)
row_right = row.row(align=True)
if dprops.bake.is_autosave_available:
row_left.enabled = False
row_left.prop(dprops.bake, "original_frame_start")
else:
row_left.prop(sprops.frame_range_custom, "value_min")
row_right.prop(sprops.frame_range_custom, "value_max")
subbox = box.box()
column = subbox.column(align=True)
column.label(text="Settings and Mesh Export:")
column.prop(sprops, "update_settings_on_resume")
indent_str = 5 * " "
subbox = subbox.box()
row = subbox.row(align=True)
row.prop(sprops, "skip_mesh_reexport_expanded",
icon="TRIA_DOWN" if sprops.skip_mesh_reexport_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Skip Mesh Re-Export:")
if sprops.skip_mesh_reexport_expanded:
flip_props = context.scene.flip_fluid
flip_objects = (flip_props.get_obstacle_objects() +
flip_props.get_fluid_objects() +
flip_props.get_inflow_objects() +
flip_props.get_outflow_objects() +
flip_props.get_force_field_objects())
num_flip_objects = len(flip_objects)
flip_object_count_limit = 128
if num_flip_objects > flip_object_count_limit:
column = subbox.column()
column.alert = True
column.label(text="Menu Unavailable", icon="ERROR")
column.label(text="This menu is only available in scenes containing " + str(flip_object_count_limit) + " FLIP objects or fewer", icon="ERROR")
column.label(text="Current number of FLIP objects: " + str(num_flip_objects), icon="ERROR")
else:
column = subbox.column()
column.label(text="Object Motion Type:")
row = column.row(align=True)
row.prop(sprops, "mesh_reexport_type_filter", expand=True)
flip_objects.sort(key=lambda x: x.name)
is_all_filter_selected = sprops.mesh_reexport_type_filter == 'MOTION_FILTER_TYPE_ALL'
if sprops.mesh_reexport_type_filter == 'MOTION_FILTER_TYPE_ALL':
filtered_objects = flip_objects
motion_type_string = "simulation"
elif sprops.mesh_reexport_type_filter == 'MOTION_FILTER_TYPE_STATIC':
filtered_objects = [x for x in flip_objects if _get_object_motion_type(self, x) == 'STATIC']
motion_type_string = "static"
elif sprops.mesh_reexport_type_filter == 'MOTION_FILTER_TYPE_KEYFRAMED':
filtered_objects = [x for x in flip_objects if _get_object_motion_type(self, x) == 'KEYFRAMED']
motion_type_string = "keyframed"
elif sprops.mesh_reexport_type_filter == 'MOTION_FILTER_TYPE_ANIMATED':
filtered_objects = [x for x in flip_objects if _get_object_motion_type(self, x) == 'ANIMATED']
motion_type_string = "animated"
if len(filtered_objects) == 0:
column.label(text=indent_str + "No " + motion_type_string + " objects found...")
if body:
subbox = body.column()
column = subbox.column(align=True)
column.label(text="Frame Range:")
row = column.row()
row.prop(sprops, "frame_range_mode", expand=True)
row = column.row(align=True)
if sprops.frame_range_mode == 'FRAME_RANGE_TIMELINE':
row_left = row.row(align=True)
row_right = row.row(align=True)
if dprops.bake.is_autosave_available:
row_left.enabled = False
row_left.prop(dprops.bake, "original_frame_start")
else:
split = column.split()
column_left = split.column(align=True)
if is_all_filter_selected:
column_animated = split.column(align=True)
row_left.prop(context.scene, "frame_start")
row_right.prop(context.scene, "frame_end")
else:
row_left = row.row(align=True)
row_right = row.row(align=True)
if dprops.bake.is_autosave_available:
row_left.enabled = False
row_left.prop(dprops.bake, "original_frame_start")
else:
row_left.prop(sprops.frame_range_custom, "value_min")
row_right.prop(sprops.frame_range_custom, "value_max")
column_middle = split.column(align=True)
column_right = split.column(align=True)
subbox = body.column()
column = subbox.column(align=True)
column.label(text="Settings and Mesh Export:")
column.prop(sprops, "update_settings_on_resume")
column_left.label(text="")
column_left.label(text="Object")
op_box = column_left.box()
op_box.label(text="")
indent_str = 5 * " "
if is_all_filter_selected:
column_animated.label(text="")
column_animated.label(text="Export Animated")
op_box = column_animated.box()
row = op_box.row(align=True)
row.alignment = 'LEFT'
row.operator("flip_fluid_operators.helper_batch_export_animated_mesh", icon='CHECKBOX_HLT', text="").enable_state = True
row.operator("flip_fluid_operators.helper_batch_export_animated_mesh", icon='CHECKBOX_DEHLT', text="").enable_state = False
row.label(text="All")
#
# Skip Re-Export Settings Panel
#
box = body.box()
header_skip_reexport, body_skip_reexport = box.panel("skip_reexport_settings", default_closed=True)
column_middle.label(text="")
column_middle.label(text="Skip Re-Export")
op_box = column_middle.box()
row = op_box.row(align=True)
row.alignment = 'LEFT'
row.operator("flip_fluid_operators.helper_batch_skip_reexport", icon='CHECKBOX_HLT', text="").enable_state = True
row.operator("flip_fluid_operators.helper_batch_skip_reexport", icon='CHECKBOX_DEHLT', text="").enable_state = False
row.label(text="All")
row_skip_reexport = header_skip_reexport.row(align=True)
row_skip_reexport.label(text="Skip Mesh Re-Export:")
column_right.label(text="Force Export")
column_right.label(text="On Next Bake")
op_box = column_right.box()
row = op_box.row(align=True)
row.alignment = 'LEFT'
row.operator("flip_fluid_operators.helper_batch_force_reexport", icon='CHECKBOX_HLT', text="").enable_state = True
row.operator("flip_fluid_operators.helper_batch_force_reexport", icon='CHECKBOX_DEHLT', text="").enable_state = False
row.label(text="All")
if body_skip_reexport:
flip_props = context.scene.flip_fluid
flip_objects = (flip_props.get_obstacle_objects() +
flip_props.get_fluid_objects() +
flip_props.get_inflow_objects() +
flip_props.get_outflow_objects() +
flip_props.get_force_field_objects())
is_export_hint_enabled = not vcu.get_addon_preferences().dismiss_export_animated_mesh_parented_relation_hint
for ob in filtered_objects:
pgroup = ob.flip_fluid.get_property_group()
column_left_row = column_left.row(align=True)
column_left_row.alignment = 'LEFT'
column_left_row.label(text=ob.name, icon="OBJECT_DATA")
num_flip_objects = len(flip_objects)
flip_object_count_limit = 128
if num_flip_objects > flip_object_count_limit:
column = body_skip_reexport.column()
column.alert = True
column.label(text="Menu Unavailable", icon="ERROR")
column.label(text="This menu is only available in scenes containing " + str(flip_object_count_limit) + " FLIP objects or fewer", icon="ERROR")
column.label(text="Current number of FLIP objects: " + str(num_flip_objects), icon="ERROR")
else:
column = body_skip_reexport.column()
column.label(text="Object Motion Type:")
row = column.row(align=True)
row.prop(sprops, "mesh_reexport_type_filter", expand=True)
is_child_object = ob.parent is not None
if is_export_hint_enabled and not pgroup.export_animated_mesh and is_child_object:
column_left_row.prop(context.scene.flip_fluid_helper, "export_animated_mesh_parent_tooltip",
icon="INFO", emboss=False, text=""
)
flip_objects.sort(key=lambda x: x.name)
is_all_filter_selected = sprops.mesh_reexport_type_filter == 'MOTION_FILTER_TYPE_ALL'
if sprops.mesh_reexport_type_filter == 'MOTION_FILTER_TYPE_ALL':
filtered_objects = flip_objects
motion_type_string = "simulation"
elif sprops.mesh_reexport_type_filter == 'MOTION_FILTER_TYPE_STATIC':
filtered_objects = [x for x in flip_objects if _get_object_motion_type(self, x) == 'STATIC']
motion_type_string = "static"
elif sprops.mesh_reexport_type_filter == 'MOTION_FILTER_TYPE_KEYFRAMED':
filtered_objects = [x for x in flip_objects if _get_object_motion_type(self, x) == 'KEYFRAMED']
motion_type_string = "keyframed"
elif sprops.mesh_reexport_type_filter == 'MOTION_FILTER_TYPE_ANIMATED':
filtered_objects = [x for x in flip_objects if _get_object_motion_type(self, x) == 'ANIMATED']
motion_type_string = "animated"
if len(filtered_objects) == 0:
column.label(text=indent_str + "No " + motion_type_string + " objects found...")
else:
split = column.split()
column_left = split.column(align=True)
if is_all_filter_selected:
column_animated = split.column(align=True)
column_middle = split.column(align=True)
column_right = split.column(align=True)
column_left.label(text="")
column_left.label(text="Object")
op_box = column_left.box()
op_box.label(text="")
if is_all_filter_selected:
column_animated.prop(pgroup, "export_animated_mesh", text="animated", toggle=True)
column_middle.prop(pgroup, "skip_reexport", text="skip", toggle=True)
column_right.prop(pgroup, "force_reexport_on_next_bake", text="force", toggle=True)
column_animated.label(text="")
column_animated.label(text="Export Animated")
op_box = column_animated.box()
row = op_box.row(align=True)
row.alignment = 'LEFT'
row.operator("flip_fluid_operators.helper_batch_export_animated_mesh", icon='CHECKBOX_HLT', text="").enable_state = True
row.operator("flip_fluid_operators.helper_batch_export_animated_mesh", icon='CHECKBOX_DEHLT', text="").enable_state = False
row.label(text="All")
subbox = box.box()
column = subbox.column(align=True)
column.label(text="Savestates:")
column.prop(sprops, "enable_savestates")
column = subbox.column(align=True)
column.enabled = sprops.enable_savestates
split = column.split()
column = split.column()
row = column.row()
row.alignment = 'RIGHT'
row.label(text="Generate savestate every")
column = split.column()
split = column.split()
column = split.column()
row = column.row(align=True)
row.prop(sprops, "savestate_interval", text="")
row.label(text="frames")
column = subbox.column(align=True)
column.enabled = sprops.enable_savestates
column.prop(sprops, "delete_outdated_savestates")
column.prop(sprops, "delete_outdated_meshes")
column_middle.label(text="")
column_middle.label(text="Skip Re-Export")
op_box = column_middle.box()
row = op_box.row(align=True)
row.alignment = 'LEFT'
row.operator("flip_fluid_operators.helper_batch_skip_reexport", icon='CHECKBOX_HLT', text="").enable_state = True
row.operator("flip_fluid_operators.helper_batch_skip_reexport", icon='CHECKBOX_DEHLT', text="").enable_state = False
row.label(text="All")
column_right.label(text="Force Export")
column_right.label(text="On Next Bake")
op_box = column_right.box()
row = op_box.row(align=True)
row.alignment = 'LEFT'
row.operator("flip_fluid_operators.helper_batch_force_reexport", icon='CHECKBOX_HLT', text="").enable_state = True
row.operator("flip_fluid_operators.helper_batch_force_reexport", icon='CHECKBOX_DEHLT', text="").enable_state = False
row.label(text="All")
is_export_hint_enabled = not vcu.get_addon_preferences().dismiss_export_animated_mesh_parented_relation_hint
for ob in filtered_objects:
pgroup = ob.flip_fluid.get_property_group()
column_left_row = column_left.row(align=True)
column_left_row.alignment = 'LEFT'
column_left_row.label(text=ob.name, icon="OBJECT_DATA")
is_child_object = ob.parent is not None
if is_export_hint_enabled and not pgroup.export_animated_mesh and is_child_object:
column_left_row.prop(context.scene.flip_fluid_helper, "export_animated_mesh_parent_tooltip",
icon="INFO", emboss=False, text=""
)
if is_all_filter_selected:
column_animated.prop(pgroup, "export_animated_mesh", text="animated", toggle=True)
column_middle.prop(pgroup, "skip_reexport", text="skip", toggle=True)
column_right.prop(pgroup, "force_reexport_on_next_bake", text="force", toggle=True)
"""
subbox = subbox.column()
row = subbox.row(align=True)
row.prop(sprops, "skip_mesh_reexport_expanded",
icon="TRIA_DOWN" if sprops.skip_mesh_reexport_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Skip Mesh Re-Export:")
if sprops.skip_mesh_reexport_expanded:
flip_props = context.scene.flip_fluid
flip_objects = (flip_props.get_obstacle_objects() +
flip_props.get_fluid_objects() +
flip_props.get_inflow_objects() +
flip_props.get_outflow_objects() +
flip_props.get_force_field_objects())
num_flip_objects = len(flip_objects)
flip_object_count_limit = 128
if num_flip_objects > flip_object_count_limit:
column = subbox.column()
column.alert = True
column.label(text="Menu Unavailable", icon="ERROR")
column.label(text="This menu is only available in scenes containing " + str(flip_object_count_limit) + " FLIP objects or fewer", icon="ERROR")
column.label(text="Current number of FLIP objects: " + str(num_flip_objects), icon="ERROR")
else:
column = subbox.column()
column.label(text="Object Motion Type:")
row = column.row(align=True)
row.prop(sprops, "mesh_reexport_type_filter", expand=True)
flip_objects.sort(key=lambda x: x.name)
is_all_filter_selected = sprops.mesh_reexport_type_filter == 'MOTION_FILTER_TYPE_ALL'
if sprops.mesh_reexport_type_filter == 'MOTION_FILTER_TYPE_ALL':
filtered_objects = flip_objects
motion_type_string = "simulation"
elif sprops.mesh_reexport_type_filter == 'MOTION_FILTER_TYPE_STATIC':
filtered_objects = [x for x in flip_objects if _get_object_motion_type(self, x) == 'STATIC']
motion_type_string = "static"
elif sprops.mesh_reexport_type_filter == 'MOTION_FILTER_TYPE_KEYFRAMED':
filtered_objects = [x for x in flip_objects if _get_object_motion_type(self, x) == 'KEYFRAMED']
motion_type_string = "keyframed"
elif sprops.mesh_reexport_type_filter == 'MOTION_FILTER_TYPE_ANIMATED':
filtered_objects = [x for x in flip_objects if _get_object_motion_type(self, x) == 'ANIMATED']
motion_type_string = "animated"
if len(filtered_objects) == 0:
column.label(text=indent_str + "No " + motion_type_string + " objects found...")
else:
split = column.split()
column_left = split.column(align=True)
if is_all_filter_selected:
column_animated = split.column(align=True)
column_middle = split.column(align=True)
column_right = split.column(align=True)
column_left.label(text="")
column_left.label(text="Object")
op_box = column_left.box()
op_box.label(text="")
if is_all_filter_selected:
column_animated.label(text="")
column_animated.label(text="Export Animated")
op_box = column_animated.box()
row = op_box.row(align=True)
row.alignment = 'LEFT'
row.operator("flip_fluid_operators.helper_batch_export_animated_mesh", icon='CHECKBOX_HLT', text="").enable_state = True
row.operator("flip_fluid_operators.helper_batch_export_animated_mesh", icon='CHECKBOX_DEHLT', text="").enable_state = False
row.label(text="All")
column_middle.label(text="")
column_middle.label(text="Skip Re-Export")
op_box = column_middle.box()
row = op_box.row(align=True)
row.alignment = 'LEFT'
row.operator("flip_fluid_operators.helper_batch_skip_reexport", icon='CHECKBOX_HLT', text="").enable_state = True
row.operator("flip_fluid_operators.helper_batch_skip_reexport", icon='CHECKBOX_DEHLT', text="").enable_state = False
row.label(text="All")
column_right.label(text="Force Export")
column_right.label(text="On Next Bake")
op_box = column_right.box()
row = op_box.row(align=True)
row.alignment = 'LEFT'
row.operator("flip_fluid_operators.helper_batch_force_reexport", icon='CHECKBOX_HLT', text="").enable_state = True
row.operator("flip_fluid_operators.helper_batch_force_reexport", icon='CHECKBOX_DEHLT', text="").enable_state = False
row.label(text="All")
is_export_hint_enabled = not vcu.get_addon_preferences().dismiss_export_animated_mesh_parented_relation_hint
for ob in filtered_objects:
pgroup = ob.flip_fluid.get_property_group()
column_left_row = column_left.row(align=True)
column_left_row.alignment = 'LEFT'
column_left_row.label(text=ob.name, icon="OBJECT_DATA")
is_child_object = ob.parent is not None
if is_export_hint_enabled and not pgroup.export_animated_mesh and is_child_object:
column_left_row.prop(context.scene.flip_fluid_helper, "export_animated_mesh_parent_tooltip",
icon="INFO", emboss=False, text=""
)
if is_all_filter_selected:
column_animated.prop(pgroup, "export_animated_mesh", text="animated", toggle=True)
column_middle.prop(pgroup, "skip_reexport", text="skip", toggle=True)
column_right.prop(pgroup, "force_reexport_on_next_bake", text="force", toggle=True)
"""
subbox = body.column()
column = subbox.column(align=True)
column.label(text="Savestates:")
column.prop(sprops, "enable_savestates")
column = subbox.column(align=True)
column.enabled = sprops.enable_savestates
split = column.split()
column = split.column()
row = column.row()
row.alignment = 'RIGHT'
row.label(text="Generate savestate every")
column = split.column()
split = column.split()
column = split.column()
row = column.row(align=True)
row.prop(sprops, "savestate_interval", text="")
row.label(text="frames")
column = subbox.column(align=True)
column.enabled = sprops.enable_savestates
column.prop(sprops, "delete_outdated_savestates")
column.prop(sprops, "delete_outdated_meshes")
def draw_resolution_settings(self, context, master_column):
def draw_simulation_settings(self, context, master_column):
obj = vcu.get_active_object(context)
dprops = obj.flip_fluid.domain
sprops = dprops.simulation
wprops = dprops.world
aprops = dprops.advanced
#
# Grid Resolution Panel
#
box = master_column.box()
column = box.column(align=True)
split = column.split(align=True)
column_left = split.column(align=True)
column_right = split.column(align=True)
row = column_left.row(align=True)
row.prop(sprops, "simulation_resolution_expanded",
icon="TRIA_DOWN" if sprops.simulation_resolution_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Grid Resolution:")
header, body = box.panel("simulation_resolution", default_closed=True)
if not sprops.simulation_resolution_expanded:
row = column_right.row(align=True)
row.prop(sprops, "resolution", text="Resolution")
else:
column = box.column(align=True)
row = header.row(align=True)
row.label(text="Grid Resolution:")
if body:
column = body.column(align=True)
split = vcu.ui_split(column, factor=0.5, align=True)
column_left = split.column(align=True)
@@ -327,7 +429,7 @@ def draw_resolution_settings(self, context, master_column):
column_right.enabled = not sprops.auto_preview_resolution
column_right.prop(sprops, "preview_resolution")
column = box.column(align=True)
column = body.column(align=True)
split = vcu.ui_split(column, factor=0.5)
column_left = split.column(align=True)
column_right = split.column(align=True)
@@ -339,7 +441,7 @@ def draw_resolution_settings(self, context, master_column):
old_resolution = max(sprops.savestate_isize, sprops.savestate_jsize, sprops.savestate_ksize)
indent = 7
subbox = box.box()
subbox = body.box()
column = subbox.column(align=True)
column.label(text="Increased resolution detected")
row = column.row()
@@ -347,22 +449,24 @@ def draw_resolution_settings(self, context, master_column):
row.label(text="Simulation will be upscaled on resume.")
column.label(text=indent*" " + " Cache resolution: " + str(old_resolution))
column.label(text=indent*" " + " Current resolution: " + str(sprops.resolution))
else:
row.prop(sprops, "resolution", text="Resolution")
#
# Grid Info Panel
#
box = master_column.box()
row = box.row(align=True)
row.prop(sprops, "grid_info_expanded",
icon="TRIA_DOWN" if sprops.grid_info_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
header, body = box.panel("grid_info", default_closed=True)
row = header.row(align=True)
row.label(text="Grid Info:")
row = row.row()
row.alignment = 'RIGHT'
row.prop(dprops.debug, "grid_display_mode", text="")
row.prop(dprops.debug, "display_simulation_grid", text="Visualize Grid")
if sprops.grid_info_expanded:
column = box.column(align=True)
if body:
column = body.column(align=True)
split = vcu.ui_split(column, factor=0.05, align=True)
column_left = split.column(align=True)
@@ -444,25 +548,17 @@ def draw_resolution_settings(self, context, master_column):
column_right.label(text=voxel_size_str)
column_right.label(text=voxel_count_str)
#
# Simulation Method Panel
#
box = master_column.box()
column = box.column(align=True)
split = column.split(align=True)
column_left = split.column(align=True)
column_right = split.column(align=True)
row = column_left.row(align=True)
row.prop(sprops, "simulation_method_expanded",
icon="TRIA_DOWN" if sprops.simulation_method_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
header, body = box.panel("simulation_method", default_closed=True)
row = header.row(align=True)
row.label(text="Simulation Method:")
if not sprops.simulation_method_expanded:
row = column_right.row()
row.prop(aprops, "velocity_transfer_method", expand=True)
pass
else:
column = box.column(align=True)
if body:
column = body.column(align=True)
row = column.row(align=True)
row.prop(aprops, "velocity_transfer_method", expand=True)
row = column.row(align=True)
@@ -470,15 +566,12 @@ def draw_resolution_settings(self, context, master_column):
row.prop(aprops, "PICFLIP_ratio", slider=True)
else:
row.label(text="")
else:
row.prop(aprops, "velocity_transfer_method", expand=True)
box = master_column.box()
row = box.row(align=True)
row.prop(sprops, "world_scale_expanded",
icon="TRIA_DOWN" if sprops.world_scale_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
#
# World Scale Panel
#
xdims, ydims, zdims = wprops.get_simulation_dimensions(context)
xdims_str = '{:.2f}'.format(round(xdims, 2))
ydims_str = '{:.2f}'.format(round(ydims, 2))
@@ -487,18 +580,21 @@ def draw_resolution_settings(self, context, master_column):
ydims_str = ydims_str.rstrip("0").rstrip(".") + "m"
zdims_str = zdims_str.rstrip("0").rstrip(".") + "m"
dimensions_str = str(xdims_str) + " x " + str(ydims_str) + " x " + str(zdims_str)
box = master_column.box()
header, body = box.panel("world_scale", default_closed=True)
row = header.row(align=True)
row.label(text="World Scale:")
row = row.row(align=True)
row.alignment = 'LEFT'
row = header.row(align=True)
row.alignment = 'RIGHT'
row.label(text=dimensions_str)
if not sprops.world_scale_expanded:
pass
else:
row = box.row(align=True)
if body:
row = body.row(align=True)
row.prop(wprops, "world_scale_mode", expand=True)
column = box.column(align=True)
column = body.column(align=True)
split = column.split(align=True)
column_left = split.column()
column_right = split.column()
@@ -514,15 +610,9 @@ def draw_resolution_settings(self, context, master_column):
row.label(text="Domain Length = ")
column_right.prop(wprops, "world_scale_absolute")
box = master_column.box()
row = box.row(align=True)
row.prop(sprops, "boundary_collisions_expanded",
icon="TRIA_DOWN" if sprops.boundary_collisions_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Domain Boundary Collisions:")
#
# Boundary Collisions Panel
#
if all(sprops.fluid_boundary_collisions):
boundary_collision_status_str = "Closed"
elif not any(sprops.fluid_boundary_collisions):
@@ -530,14 +620,17 @@ def draw_resolution_settings(self, context, master_column):
else:
boundary_collision_status_str = "Mixed"
row = row.row(align=True)
box = master_column.box()
header, body = box.panel("boundary_collisions", default_closed=True)
row = header.row(align=True)
row.label(text="Domain Boundary Collisions:")
row = header.row(align=True)
row.alignment = 'RIGHT'
row.label(text=boundary_collision_status_str)
if not sprops.boundary_collisions_expanded:
pass
else:
column = box.column(align=True)
if body:
column = body.column(align=True)
row = column.row(align=True)
row.prop(sprops, "fluid_boundary_collisions", index=0, text="X ")
row.prop(sprops, "fluid_boundary_collisions", index=1, text="X+")
@@ -550,99 +643,86 @@ def draw_resolution_settings(self, context, master_column):
column.prop(sprops, "fluid_open_boundary_width", slider=True)
def _get_object_motion_type(self, obj):
props = obj.flip_fluid.get_property_group()
if hasattr(props, 'export_animated_mesh') and props.export_animated_mesh:
return 'ANIMATED'
if export_utils.is_object_keyframe_animated(obj):
return 'KEYFRAMED'
return 'STATIC'
#
# Draw Frame Rate and Time Scale Panel
#
fps_str = "{:.2f}".format(sprops.get_frame_rate()) + " FPS"
row = row.row(align =True)
box = master_column.box()
header, body = box.panel("frame_rate_and_time_scale", default_closed=True)
def draw_time_settings(self, context, box):
obj = vcu.get_active_object(context)
sprops = obj.flip_fluid.domain.simulation
row = box.row(align=True)
row.prop(sprops, "frame_rate_and_time_scale_expanded",
icon="TRIA_DOWN" if sprops.frame_rate_and_time_scale_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row = header.row(align=True)
row.label(text="Frame Rate and Time Scale:")
row = row.row(align=True)
row.alignment = 'RIGHT'
row.label(text=fps_str)
if not sprops.frame_rate_and_time_scale_expanded:
fps_str = "{:.2f}".format(sprops.get_frame_rate()) + " FPS"
row = row.row(align =True)
row.alignment = 'RIGHT'
row.label(text=fps_str)
return
if body:
column = body.column(align=True)
column.label(text="Frame Rate:")
column = box.column(align=True)
column.label(text="Frame Rate:")
row = column.row(align=True)
row.prop(sprops, "frame_rate_mode", expand=True)
column = column.column(align=True)
column.enabled = sprops.frame_rate_mode == 'FRAME_RATE_MODE_CUSTOM'
if sprops.frame_rate_mode == 'FRAME_RATE_MODE_SCENE':
column.prop(context.scene.render, "fps", text="Scene Frame Rate")
else:
column.prop(sprops, "frame_rate_custom", text="Custom Frame Rate")
column = box.column(align=True)
column.label(text="Time Scale:")
row = column.row(align=True)
row.prop(sprops, "time_scale_mode", expand=True)
column = column.column(align=True)
if sprops.time_scale_mode == 'TIME_SCALE_MODE_CUSTOM':
column.prop(sprops, "time_scale", text="Custom Time Scale")
elif sprops.time_scale_mode == 'TIME_SCALE_MODE_RIGID_BODY':
if bpy.context.scene.rigidbody_world is not None:
column.prop(bpy.context.scene.rigidbody_world, "time_scale", text="Rigid Body Time Scale")
row = column.row(align=True)
row.prop(sprops, "frame_rate_mode", expand=True)
column = column.column(align=True)
column.enabled = sprops.frame_rate_mode == 'FRAME_RATE_MODE_CUSTOM'
if sprops.frame_rate_mode == 'FRAME_RATE_MODE_SCENE':
column.prop(context.scene.render, "fps", text="Scene Frame Rate")
else:
column.prop(sprops, "frame_rate_custom", text="Custom Frame Rate")
column = body.column(align=True)
column.label(text="Time Scale:")
row = column.row(align=True)
row.prop(sprops, "time_scale_mode", expand=True)
column = column.column(align=True)
if sprops.time_scale_mode == 'TIME_SCALE_MODE_CUSTOM':
column.prop(sprops, "time_scale", text="Custom Time Scale")
elif sprops.time_scale_mode == 'TIME_SCALE_MODE_RIGID_BODY':
if bpy.context.scene.rigidbody_world is not None:
column.prop(bpy.context.scene.rigidbody_world, "time_scale", text="Rigid Body Time Scale")
else:
row = column.row(align=True)
row.label(text="No Rigid Body World: ")
row.operator("rigidbody.world_add")
elif sprops.time_scale_mode == 'TIME_SCALE_MODE_SOFT_BODY':
split = column.split(align=True)
column_left = split.column(align=True)
column_right = split.column(align=True)
column_left.label(text="Soft Body Object:")
column_right.prop(sprops, "time_scale_object_soft_body", text="")
row = column.row(align=True)
row.label(text="No Rigid Body World: ")
row.operator("rigidbody.world_add")
elif sprops.time_scale_mode == 'TIME_SCALE_MODE_SOFT_BODY':
split = column.split(align=True)
column_left = split.column(align=True)
column_right = split.column(align=True)
column_left.label(text="Soft Body Object:")
column_right.prop(sprops, "time_scale_object_soft_body", text="")
row = column.row(align=True)
soft_body_modifier = sprops.get_selected_time_scale_object_soft_body_modifier()
if soft_body_modifier is not None:
row.prop(soft_body_modifier.settings, "speed", text="Soft Body Time Scale")
else:
if sprops.time_scale_object_soft_body is not None:
row.label(text="No soft body simulation found on object")
soft_body_modifier = sprops.get_selected_time_scale_object_soft_body_modifier()
if soft_body_modifier is not None:
row.prop(soft_body_modifier.settings, "speed", text="Soft Body Time Scale")
else:
row.label(text="No soft body object selected")
if sprops.time_scale_object_soft_body is not None:
row.label(text="No soft body simulation found on object")
else:
row.label(text="No soft body object selected")
elif sprops.time_scale_mode == 'TIME_SCALE_MODE_CLOTH':
split = column.split(align=True)
column_left = split.column(align=True)
column_right = split.column(align=True)
column_left.label(text="Cloth Object:")
column_right.prop(sprops, "time_scale_object_cloth", text="")
row = column.row(align=True)
cloth_modifier = sprops.get_selected_time_scale_object_cloth_modifier()
if cloth_modifier is not None:
row.prop(cloth_modifier.settings, "time_scale", text="Cloth Time Scale")
else:
if sprops.time_scale_object_cloth is not None:
row.label(text="No cloth simulation found on object")
elif sprops.time_scale_mode == 'TIME_SCALE_MODE_CLOTH':
split = column.split(align=True)
column_left = split.column(align=True)
column_right = split.column(align=True)
column_left.label(text="Cloth Object:")
column_right.prop(sprops, "time_scale_object_cloth", text="")
row = column.row(align=True)
cloth_modifier = sprops.get_selected_time_scale_object_cloth_modifier()
if cloth_modifier is not None:
row.prop(cloth_modifier.settings, "time_scale", text="Cloth Time Scale")
else:
row.label(text="No cloth object selected")
if sprops.time_scale_object_cloth is not None:
row.label(text="No cloth simulation found on object")
else:
row.label(text="No cloth object selected")
elif sprops.time_scale_mode == 'TIME_SCALE_MODE_FLUID':
if vcu.is_blender_282():
elif sprops.time_scale_mode == 'TIME_SCALE_MODE_FLUID':
split = column.split(align=True)
column_left = split.column(align=True)
column_right = split.column(align=True)
@@ -658,9 +738,15 @@ def draw_time_settings(self, context, box):
row.label(text="No Mantaflow domain found on object")
else:
row.label(text="No Mantaflow domain object selected")
else:
column.label(text="Mantaflow fluid simulation time scale mode")
column.label(text="only supported in Blender 2.82 or later")
def _get_object_motion_type(self, obj):
props = obj.flip_fluid.get_property_group()
if hasattr(props, 'export_animated_mesh') and props.export_animated_mesh:
return 'ANIMATED'
if export_utils.is_object_keyframe_animated(obj):
return 'KEYFRAMED'
return 'STATIC'
class FLIPFLUID_PT_DomainTypePanel(bpy.types.Panel):
@@ -700,10 +786,7 @@ class FLIPFLUID_PT_DomainTypePanel(bpy.types.Panel):
draw_more_bake_settings(self, context, box)
column = self.layout.column()
draw_resolution_settings(self, context, column)
box = self.layout.box()
draw_time_settings(self, context, box)
draw_simulation_settings(self, context, column)
def register():
@@ -54,17 +54,16 @@ def draw_frame_info_simulation_stats(self, context, box):
sprops = vcu.get_active_object(context).flip_fluid.domain.stats
simprops = vcu.get_active_object(context).flip_fluid.domain.simulation
subbox = box.box()
row = subbox.row()
row.prop(sprops, "frame_info_simulation_stats_expanded",
icon="TRIA_DOWN" if sprops.frame_info_simulation_stats_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Simulation Stats")
#
# Simulation Frame Stats Panel
#
box = box.box()
header, body = box.panel("simulation_frame_stats_settings", default_closed=False)
if sprops.frame_info_simulation_stats_expanded:
column = subbox.column()
row = header.row(align=True)
row.label(text="Simulation Stats:")
if body:
column = body.column()
split = column.split()
column = split.column()
column.label(text="Frame ID:")
@@ -102,30 +101,27 @@ def draw_frame_info_simulation_stats(self, context, box):
def draw_frame_info_solver_stats(self, context, box):
sprops = vcu.get_active_object(context).flip_fluid.domain.stats
subbox = box.box()
row = subbox.row()
row.prop(sprops, "frame_info_solver_stats_expanded",
icon="TRIA_DOWN" if sprops.frame_info_solver_stats_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Solver Stats")
#
# Solver Frame Stats Panel
#
stress_threshold = 80.0
if sprops.frame_info_solver_stats_expanded:
box = box.box()
header, body = box.panel("solver_frame_stats_settings", default_closed=False)
row = header.row(align=True)
row.label(text="Solver Stats:")
if body:
if sprops.frame_pressure_solver_enabled:
stress_threshold = 80.0
#
# Pressure Solver Frame Stats Panel
#
header_pressure, body_pressure = body.panel("pressure_solver_frame_stats_settings", default_closed=False)
stat_box = subbox.box()
row = stat_box.row()
row.prop(sprops, "frame_info_pressure_solver_stats_expanded",
icon="TRIA_DOWN" if sprops.frame_info_pressure_solver_stats_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Pressure Solver")
if sprops.frame_info_pressure_solver_stats_expanded:
column = stat_box.column(align=True)
row_pressure = header_pressure.row(align=True)
row_pressure.label(text="Pressure Solver:")
if body_pressure:
column = body_pressure.column(align=True)
split = column.split()
column1 = split.column(align=True)
column2 = split.column(align=True)
@@ -157,17 +153,15 @@ def draw_frame_info_solver_stats(self, context, box):
row.prop(sprops.frame_pressure_solver_stress, "stress_level", slider=True, text=stress_status)
if sprops.frame_viscosity_solver_enabled:
stat_box = subbox.box()
row = stat_box.row()
row.prop(sprops, "frame_info_viscosity_solver_stats_expanded",
icon="TRIA_DOWN" if sprops.frame_info_viscosity_solver_stats_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Viscosity Solver")
#
# Viscosity Solver Frame Stats Panel
#
header_viscosity, body_viscosity = body.panel("viscosity_solver_frame_stats_settings", default_closed=False)
if sprops.frame_info_viscosity_solver_stats_expanded:
column = stat_box.column(align=True)
row_viscosity = header_viscosity.row(align=True)
row_viscosity.label(text="Viscosity Solver:")
if body_viscosity:
column = body_viscosity.column(align=True)
column.alert = not sprops.frame_viscosity_solver_success
split = column.split()
@@ -204,17 +198,16 @@ def draw_frame_info_solver_stats(self, context, box):
def draw_frame_info_timing_stats(self, context, box):
sprops = vcu.get_active_object(context).flip_fluid.domain.stats
subbox = box.box()
row = subbox.row()
row.prop(sprops, "frame_info_timing_stats_expanded",
icon="TRIA_DOWN" if sprops.frame_info_timing_stats_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Timing Stats")
#
# Timing Frame Stats Panel
#
box = box.box()
header, body = box.panel("timing_frame_stats_settings", default_closed=False)
if sprops.frame_info_timing_stats_expanded:
column = subbox.column()
row = header.row(align=True)
row.label(text="Timing Stats:")
if body:
column = body.column()
split = vcu.ui_split(column, factor=0.75)
column = split.column(align = True)
column.prop(sprops.time_mesh, "pct", slider = True, text = "Mesh Generation")
@@ -246,7 +239,7 @@ def draw_frame_info_timing_stats(self, context, box):
sprops.time_diffuse.time + sprops.time_viscosity.time +
sprops.time_objects.time + sprops.time_other.time)
column = subbox.column()
column = body.column()
split = column.split()
column = split.column()
column = split.column()
@@ -261,17 +254,16 @@ def draw_frame_info_mesh_stats(self, context, box):
sprops = vcu.get_active_object(context).flip_fluid.domain.stats
simprops = vcu.get_active_object(context).flip_fluid.domain.simulation
subbox = box.box()
row = subbox.row()
row.prop(sprops, "frame_info_mesh_stats_expanded",
icon="TRIA_DOWN" if sprops.frame_info_mesh_stats_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Mesh Stats")
#
# Mesh Frame Stats Panel
#
box = box.box()
header, body = box.panel("mesh_frame_stats_settings", default_closed=False)
if sprops.frame_info_mesh_stats_expanded:
column = subbox.column()
row = header.row(align=True)
row.label(text="Mesh Stats:")
if body:
column = body.column()
split = column.split()
column1 = split.column()
column2 = split.column()
@@ -368,6 +360,13 @@ def draw_frame_info_mesh_stats(self, context, box):
column4.label(text=format_bytes(sprops.surfaceviscosity_mesh.bytes.get()))
total_bytes += sprops.surfaceviscosity_mesh.bytes.get()
if sprops.surfacedensity_mesh.enabled:
column1.label(text="Density")
column2.label(text=format_number(sprops.surfacedensity_mesh.verts))
column3.label(text="")
column4.label(text=format_bytes(sprops.surfacedensity_mesh.bytes.get()))
total_bytes += sprops.surfacedensity_mesh.bytes.get()
if sprops.foam_mesh.enabled:
column1.label(text="Foam")
column2.label(text=format_number(sprops.foam_mesh.verts))
@@ -578,6 +577,20 @@ def draw_frame_info_mesh_stats(self, context, box):
column4.label(text=format_bytes(sprops.fluid_particle_viscosity_mesh.bytes.get()))
total_bytes += sprops.fluid_particle_viscosity_mesh.bytes.get()
if sprops.fluid_particle_density_mesh.enabled:
column1.label(text="Fluid Particles Density")
column2.label(text=format_number(sprops.fluid_particle_density_mesh.verts))
column3.label(text="")
column4.label(text=format_bytes(sprops.fluid_particle_density_mesh.bytes.get()))
total_bytes += sprops.fluid_particle_density_mesh.bytes.get()
if sprops.fluid_particle_density_average_mesh.enabled:
column1.label(text="Fluid Particles Density Average")
column2.label(text=format_number(sprops.fluid_particle_density_average_mesh.verts))
column3.label(text="")
column4.label(text=format_bytes(sprops.fluid_particle_density_average_mesh.bytes.get()))
total_bytes += sprops.fluid_particle_density_average_mesh.bytes.get()
if sprops.fluid_particle_whitewater_proximity_mesh.enabled:
column1.label(text="Fluid Particles Whitewater Proximity")
column2.label(text=format_number(sprops.fluid_particle_whitewater_proximity_mesh.verts))
@@ -627,7 +640,6 @@ def draw_frame_info(self, context, box):
else:
box.label(text="Data Not Available (frame " + str(sprops.current_info_frame) + ")", icon='ERROR')
box.separator()
draw_frame_info_simulation_stats(self, context, box)
draw_frame_info_solver_stats(self, context, box)
draw_frame_info_timing_stats(self, context, box)
@@ -639,20 +651,19 @@ def draw_cache_info_simulation_stats(self, context, box):
sprops = dprops.stats
simprops = dprops.simulation
subbox = box.box()
row = subbox.row()
row.prop(sprops, "cache_info_simulation_stats_expanded",
icon="TRIA_DOWN" if sprops.cache_info_simulation_stats_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Simulation Stats")
#
# Simulation Cache Stats Panel
#
box = box.box()
header, body = box.panel("simulation_cache_stats_settings", default_closed=False)
if sprops.cache_info_simulation_stats_expanded:
row = header.row(align=True)
row.label(text="Simulation Stats:")
if body:
num_frames = dprops.simulation.frame_end - sprops.frame_start + 1
num_baked_frames = sprops.num_cache_frames
column = subbox.column()
column = body.column()
split = column.split()
column = split.column()
column.label(text="Completed Frames:")
@@ -672,7 +683,7 @@ def draw_cache_info_simulation_stats(self, context, box):
column.label(text=str(sprops.average_performance_score))
if dprops.bake.is_simulation_running:
column = subbox.column()
column = body.column()
split = column.split()
column = split.column()
@@ -690,119 +701,111 @@ def draw_cache_info_solver_stats(self, context, box):
sprops = dprops.stats
simprops = dprops.simulation
subbox = box.box()
row = subbox.row()
row.prop(sprops, "cache_info_solver_stats_expanded",
icon="TRIA_DOWN" if sprops.cache_info_solver_stats_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Solver Stats")
#
# Solver Cache Stats Panel
#
box = box.box()
header, body = box.panel("solver_cache_stats_settings", default_closed=False)
if not sprops.cache_info_solver_stats_expanded:
return
row = header.row(align=True)
row.label(text="Solver Stats:")
if body:
if sprops.pressure_solver_enabled:
#
# Pressure Solver Cache Stats Panel
#
header_pressure, body_pressure = body.panel("pressure_solver_cache_stats_settings", default_closed=False)
if sprops.pressure_solver_enabled:
pressure_box = subbox.box()
row = pressure_box.row()
row.prop(sprops, "cache_info_pressure_solver_stats_expanded",
icon="TRIA_DOWN" if sprops.cache_info_pressure_solver_stats_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Pressure Solver")
row_pressure = header_pressure.row(align=True)
row_pressure.label(text="Pressure Solver:")
if body_pressure:
column = body_pressure.column(align=True)
split = column.split(align=True)
column_left = split.column(align=True)
column_middle = split.column(align=True)
column_right = split.column(align=True)
if sprops.cache_info_pressure_solver_stats_expanded:
column = pressure_box.column(align=True)
split = column.split(align=True)
column_left = split.column(align=True)
column_middle = split.column(align=True)
column_right = split.column(align=True)
column_left.label(text="Solver Failures:")
column_left.label(text="Max Iterations:")
column_left.label(text="Max Error:")
column_left.label(text="Max Stress:")
column_left.label(text="Solver Failures:")
column_left.label(text="Max Iterations:")
column_left.label(text="Max Error:")
column_left.label(text="Max Stress:")
failure_str = str(sprops.pressure_solver_failures) + " failures / " + str(sprops.pressure_solver_steps) + " steps"
iterations_str = str(sprops.pressure_solver_max_iterations)
error_str = '{0:.12f}'.format(sprops.pressure_solver_max_error)
stress_threshold = 80.0
stress_state = "OK"
if sprops.pressure_solver_max_stress > stress_threshold:
stress_state = "HIGH"
if sprops.pressure_solver_max_stress >= 99.999:
stress_state = "MAX"
stress_str = '{0:.1f}'.format(sprops.pressure_solver_max_stress) + "% " + stress_state
failure_str = str(sprops.pressure_solver_failures) + " failures / " + str(sprops.pressure_solver_steps) + " steps"
iterations_str = str(sprops.pressure_solver_max_iterations)
error_str = '{0:.12f}'.format(sprops.pressure_solver_max_error)
stress_threshold = 80.0
stress_state = "OK"
if sprops.pressure_solver_max_stress > stress_threshold:
stress_state = "HIGH"
if sprops.pressure_solver_max_stress >= 99.999:
stress_state = "MAX"
stress_str = '{0:.1f}'.format(sprops.pressure_solver_max_stress) + "% " + stress_state
column_middle.label(text=failure_str)
column_middle.label(text=iterations_str)
column_middle.label(text=error_str)
column_middle.label(text=stress_str)
column_middle.label(text=failure_str)
column_middle.label(text=iterations_str)
column_middle.label(text=error_str)
column_middle.label(text=stress_str)
column_right.label(text="")
column_right.label(text="(frame " + str(sprops.pressure_solver_max_iterations_frame) + ")")
column_right.label(text="(frame " + str(sprops.pressure_solver_max_error_frame) + ")")
column_right.label(text="(frame " + str(sprops.pressure_solver_max_stress_frame) + ")")
column_right.label(text="")
column_right.label(text="(frame " + str(sprops.pressure_solver_max_iterations_frame) + ")")
column_right.label(text="(frame " + str(sprops.pressure_solver_max_error_frame) + ")")
column_right.label(text="(frame " + str(sprops.pressure_solver_max_stress_frame) + ")")
if sprops.viscosity_solver_enabled:
#
# Viscosity Solver Cache Stats Panel
#
header_viscosity, body_viscosity = body.panel("viscosity_solver_cache_stats_settings", default_closed=False)
if sprops.viscosity_solver_enabled:
viscosity_box = subbox.box()
row = viscosity_box.row()
row.prop(sprops, "cache_info_viscosity_solver_stats_expanded",
icon="TRIA_DOWN" if sprops.cache_info_viscosity_solver_stats_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Viscosity Solver")
row_viscosity = header_viscosity.row(align=True)
row_viscosity.label(text="Viscosity Solver:")
if body_viscosity:
column = body_viscosity.column(align=True)
split = column.split(align=True)
column_left = split.column(align=True)
column_middle = split.column(align=True)
column_right = split.column(align=True)
if sprops.cache_info_viscosity_solver_stats_expanded:
column = viscosity_box.column(align=True)
split = column.split(align=True)
column_left = split.column(align=True)
column_middle = split.column(align=True)
column_right = split.column(align=True)
column_left.label(text="Solver Failures:")
column_left.label(text="Max Iterations:")
column_left.label(text="Max Error:")
column_left.label(text="Max Stress:")
column_left.label(text="Solver Failures:")
column_left.label(text="Max Iterations:")
column_left.label(text="Max Error:")
column_left.label(text="Max Stress:")
failure_str = str(sprops.viscosity_solver_failures) + " failures / " + str(sprops.viscosity_solver_steps) + " steps"
iterations_str = str(sprops.viscosity_solver_max_iterations)
error_str = '{0:.12f}'.format(sprops.viscosity_solver_max_error)
stress_threshold = 80.0
stress_state = "OK"
if sprops.viscosity_solver_max_stress > stress_threshold:
stress_state = "HIGH"
if sprops.viscosity_solver_max_stress >= 99.999:
stress_state = "MAX"
stress_str = '{0:.1f}'.format(sprops.viscosity_solver_max_stress) + "% " + stress_state
failure_str = str(sprops.viscosity_solver_failures) + " failures / " + str(sprops.viscosity_solver_steps) + " steps"
iterations_str = str(sprops.viscosity_solver_max_iterations)
error_str = '{0:.12f}'.format(sprops.viscosity_solver_max_error)
stress_threshold = 80.0
stress_state = "OK"
if sprops.viscosity_solver_max_stress > stress_threshold:
stress_state = "HIGH"
if sprops.viscosity_solver_max_stress >= 99.999:
stress_state = "MAX"
stress_str = '{0:.1f}'.format(sprops.viscosity_solver_max_stress) + "% " + stress_state
column_middle.label(text=failure_str)
column_middle.label(text=iterations_str)
column_middle.label(text=error_str)
column_middle.label(text=stress_str)
column_middle.label(text=failure_str)
column_middle.label(text=iterations_str)
column_middle.label(text=error_str)
column_middle.label(text=stress_str)
column_right.label(text="")
column_right.label(text="(frame " + str(sprops.viscosity_solver_max_iterations_frame) + ")")
column_right.label(text="(frame " + str(sprops.viscosity_solver_max_error_frame) + ")")
column_right.label(text="(frame " + str(sprops.viscosity_solver_max_stress_frame) + ")")
column_right.label(text="")
column_right.label(text="(frame " + str(sprops.viscosity_solver_max_iterations_frame) + ")")
column_right.label(text="(frame " + str(sprops.viscosity_solver_max_error_frame) + ")")
column_right.label(text="(frame " + str(sprops.viscosity_solver_max_stress_frame) + ")")
def draw_cache_info_timing_stats(self, context, box):
sprops = vcu.get_active_object(context).flip_fluid.domain.stats
subbox = box.box()
row = subbox.row()
row.prop(sprops, "cache_info_timing_stats_expanded",
icon="TRIA_DOWN" if sprops.cache_info_timing_stats_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Timing Stats")
#
# Timing Cache Stats Panel
#
box = box.box()
header, body = box.panel("timing_cache_stats_settings", default_closed=False)
if sprops.cache_info_timing_stats_expanded:
column = subbox.column()
row = header.row(align=True)
row.label(text="Timing Stats:")
if body:
column = body.column()
split = vcu.ui_split(column, factor=0.75)
column = split.column(align=True)
column.prop(sprops.time_mesh, "pct", slider=True, text="Mesh Generation")
@@ -834,7 +837,7 @@ def draw_cache_info_timing_stats(self, context, box):
sprops.time_diffuse.time + sprops.time_viscosity.time +
sprops.time_objects.time + sprops.time_other.time)
column = subbox.column()
column = body.column()
split = column.split()
column = split.column()
column = split.column()
@@ -848,17 +851,16 @@ def draw_cache_info_timing_stats(self, context, box):
def draw_cache_info_mesh_stats(self, context, box):
sprops = vcu.get_active_object(context).flip_fluid.domain.stats
subbox = box.box()
row = subbox.row()
row.prop(sprops, "cache_info_mesh_stats_expanded",
icon="TRIA_DOWN" if sprops.cache_info_mesh_stats_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Mesh Stats")
#
# Mesh Cache Stats Panel
#
box = box.box()
header, body = box.panel("mesh_cache_stats_settings", default_closed=False)
if sprops.cache_info_mesh_stats_expanded:
column = subbox.column()
row = header.row(align=True)
row.label(text="Mesh Stats:")
if body:
column = body.column()
split = vcu.ui_split(column, factor=0.5)
column1 = split.column()
column2 = split.column()
@@ -875,6 +877,7 @@ def draw_cache_info_mesh_stats(self, context, box):
sprops.surfacecolor_mesh.enabled or
sprops.surfacesourceid_mesh.enabled or
sprops.surfaceviscosity_mesh.enabled or
sprops.surfacedensity_mesh.enabled or
sprops.foam_mesh.enabled or
sprops.bubble_mesh.enabled or
sprops.spray_mesh.enabled or
@@ -904,6 +907,8 @@ def draw_cache_info_mesh_stats(self, context, box):
sprops.fluid_particle_age_mesh.enabled or
sprops.fluid_particle_lifetime_mesh.enabled or
sprops.fluid_particle_viscosity_mesh.enabled or
sprops.fluid_particle_density_mesh.enabled or
sprops.fluid_particle_density_average_mesh.enabled or
sprops.fluid_particle_whitewater_proximity_mesh.enabled or
sprops.fluid_particle_source_id_mesh.enabled or
sprops.fluid_particle_uid_mesh.enabled or
@@ -988,6 +993,12 @@ def draw_cache_info_mesh_stats(self, context, box):
row_count += 1
total_size += sprops.surfaceviscosity_mesh.bytes.get()
if sprops.surfacedensity_mesh.enabled:
column1.label(text="Density")
column2.label(text=format_bytes(sprops.surfacedensity_mesh.bytes.get()))
row_count += 1
total_size += sprops.surfacedensity_mesh.bytes.get()
if sprops.foam_mesh.enabled:
column1.label(text="Foam")
column2.label(text=format_bytes(sprops.foam_mesh.bytes.get()))
@@ -1168,6 +1179,18 @@ def draw_cache_info_mesh_stats(self, context, box):
row_count += 1
total_size += sprops.fluid_particle_viscosity_mesh.bytes.get()
if sprops.fluid_particle_density_mesh.enabled:
column1.label(text="Fluid Particles Density")
column2.label(text=format_bytes(sprops.fluid_particle_density_mesh.bytes.get()))
row_count += 1
total_size += sprops.fluid_particle_density_mesh.bytes.get()
if sprops.fluid_particle_density_average_mesh.enabled:
column1.label(text="Fluid Particles Density Average")
column2.label(text=format_bytes(sprops.fluid_particle_density_average_mesh.bytes.get()))
row_count += 1
total_size += sprops.fluid_particle_density_average_mesh.bytes.get()
if sprops.fluid_particle_whitewater_proximity_mesh.enabled:
column1.label(text="Fluid Particles Whitewater Proximity")
column2.label(text=format_bytes(sprops.fluid_particle_whitewater_proximity_mesh.bytes.get()))
@@ -1193,7 +1216,7 @@ def draw_cache_info_mesh_stats(self, context, box):
total_size += sprops.obstacle_mesh.bytes.get()
if stats_exist:
column = subbox.column()
column = body.column()
split = column.split()
column1 = split.column()
column2 = split.column()
@@ -31,61 +31,33 @@ def _draw_geometry_attributes_menu(self, context):
obj = vcu.get_active_object(context)
sprops = obj.flip_fluid.domain.surface
rprops = obj.flip_fluid.domain.render
is_surface_mesh_generation_enabled = sprops.enable_surface_mesh_generation
#
# Geometry Attributes
#
is_preview_mode_enabled = rprops.viewport_display == 'DISPLAY_PREVIEW'
is_attributes_enabled = (
sprops.enable_velocity_vector_attribute or
sprops.enable_speed_attribute or
sprops.enable_vorticity_vector_attribute or
sprops.enable_color_attribute or
sprops.enable_age_attribute or
sprops.enable_lifetime_attribute or
sprops.enable_whitewater_proximity_attribute or
sprops.enable_source_id_attribute or
sprops.enable_viscosity_attribute
)
box = self.layout.box()
row = box.row(align=True)
row.alert = not sprops.enable_surface_mesh_generation
row.prop(sprops, "geometry_attributes_expanded",
icon="TRIA_DOWN" if sprops.geometry_attributes_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
header, body = box.panel("geometry_attributes", default_closed=True)
row = header.row(align=True)
row.alert = not is_surface_mesh_generation_enabled
row.label(text="Surface Attributes:")
if sprops.geometry_attributes_expanded:
prefs = vcu.get_addon_preferences()
if not prefs.is_extra_features_enabled():
warn_box = box.box()
warn_column = warn_box.column(align=True)
warn_column.enabled = True
warn_column.label(text=" This feature is affected by a current bug in Blender.", icon='ERROR')
warn_column.label(text=" The Extra Features option must be enabled in preferences")
warn_column.label(text=" to use this feature.")
warn_column.separator()
warn_column.prop(prefs, "enable_extra_features", text="Enable Extra Features in Preferences")
warn_column.separator()
warn_column.operator(
"wm.url_open",
text="Important Info and Limitations",
icon="WORLD"
).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Preferences-Menu-Settings#developer-tools"
return
if not vcu.is_blender_293():
column = box.column(align=True)
column.enabled = False
column.label(text="Geometry attribute features for the fluid surface are only available in", icon='ERROR')
column.label(text="Blender 2.93 or later. Blender 3.1 or later recommended.", icon='ERROR')
return
is_preview_mode_enabled = rprops.viewport_display == 'DISPLAY_PREVIEW'
is_attributes_enabled = (
sprops.enable_velocity_vector_attribute or
sprops.enable_speed_attribute or
sprops.enable_vorticity_vector_attribute or
sprops.enable_color_attribute or
sprops.enable_age_attribute or
sprops.enable_lifetime_attribute or
sprops.enable_whitewater_proximity_attribute or
sprops.enable_source_id_attribute or
sprops.enable_viscosity_attribute
)
if body:
if is_preview_mode_enabled and is_attributes_enabled:
row = box.row(align=True)
row = body.row(align=True)
row.alert = True
row.alignment = 'LEFT'
row.prop(sprops, "preview_mode_attributes_tooltip", icon="QUESTION", emboss=False, text="")
@@ -94,17 +66,14 @@ def _draw_geometry_attributes_menu(self, context):
#
# Velocity Attributes
#
subbox = box.box()
row = subbox.row(align=True)
row.prop(sprops, "velocity_attributes_expanded",
icon="TRIA_DOWN" if sprops.velocity_attributes_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Velocity Based Attributes:")
box = body.box()
header_velocity, body_velocity = box.panel("velocity_attributes", default_closed=True)
if sprops.velocity_attributes_expanded:
column = subbox.column(align=True)
row_velocity = header_velocity.row(align=True)
row_velocity.alert = not is_surface_mesh_generation_enabled
row_velocity.label(text="Velocity Based Attributes:")
if body_velocity:
column = body_velocity.column(align=True)
split = column.split(align=True)
column_left = split.column(align=True)
column_right = split.column(align=True)
@@ -119,7 +88,7 @@ def _draw_geometry_attributes_menu(self, context):
column.separator()
column.operator("flip_fluid_operators.helper_initialize_motion_blur")
else:
row = row.row(align=True)
row = row_velocity.row(align=True)
row.alignment = 'RIGHT'
row.prop(sprops, "enable_velocity_vector_attribute", text="Velocity")
row.prop(sprops, "enable_speed_attribute", text="Speed")
@@ -128,17 +97,14 @@ def _draw_geometry_attributes_menu(self, context):
#
# Color Attributes
#
subbox = box.box()
row = subbox.row(align=True)
row.prop(sprops, "color_attributes_expanded",
icon="TRIA_DOWN" if sprops.color_attributes_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Color and Mixing Attributes:")
box = body.box()
header_color, body_color = box.panel("color_attributes", default_closed=True)
if sprops.color_attributes_expanded:
column = subbox.column(align=True)
row_color = header_color.row(align=True)
row_color.alert = not is_surface_mesh_generation_enabled
row_color.label(text="Color and Mixing Attributes:")
if body_color:
column = body_color.column(align=True)
split = column.split(align=True)
column_left = split.column(align=True)
column_right = split.column(align=True)
@@ -146,7 +112,7 @@ def _draw_geometry_attributes_menu(self, context):
if sprops.show_smoothing_radius_in_ui:
column_right.prop(sprops, "color_attribute_radius", text="Smoothing", slider=True)
column = subbox.column(align=True)
column = body_color.column(align=True)
split = column.split(align=True)
column_left = split.column(align=True)
column_right = split.column(align=True)
@@ -155,7 +121,7 @@ def _draw_geometry_attributes_menu(self, context):
column_right.enabled = sprops.enable_color_attribute and sprops.enable_color_attribute_mixing
column_right.prop(sprops, "color_attribute_mixing_rate", text="Mix Rate", slider=True)
column = subbox.column(align=True)
column = body_color.column(align=True)
column.enabled = sprops.enable_color_attribute and sprops.enable_color_attribute_mixing
column.label(text="Mixing Mode:")
row = column.row(align=True)
@@ -178,10 +144,10 @@ def _draw_geometry_attributes_menu(self, context):
text="Open Preferences", icon="PREFERENCES"
).view_mode = 'PREFERENCES_MENU_VIEW_MIXBOX'
else:
row = row.row(align=True)
row = row_color.row(align=True)
row.alignment = 'RIGHT'
row.prop(sprops, "enable_color_attribute", text="Color")
row = row.row(align=True)
row = row_color.row(align=True)
row.alignment = 'RIGHT'
row.enabled = sprops.enable_color_attribute
row.prop(sprops, "enable_color_attribute_mixing", text="Mixing")
@@ -189,17 +155,14 @@ def _draw_geometry_attributes_menu(self, context):
#
# Other Attributes
#
subbox = box.box()
row = subbox.row(align=True)
row.prop(sprops, "other_attributes_expanded",
icon="TRIA_DOWN" if sprops.other_attributes_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Other Attributes:")
box = body.box()
header_other, body_other = box.panel("other_attributes", default_closed=True)
if sprops.other_attributes_expanded:
column = subbox.column(align=True)
row_other = header_other.row(align=True)
row_other.alert = not is_surface_mesh_generation_enabled
row_other.label(text="Other Attributes:")
if body_other:
column = body_other.column(align=True)
row = column.row(align=True)
row.prop(sprops, "enable_age_attribute", text="Age Attributes")
if sprops.show_smoothing_radius_in_ui:
@@ -217,7 +180,7 @@ def _draw_geometry_attributes_menu(self, context):
row.prop(sprops, "whitewater_proximity_attribute_radius", text="Smoothing", slider=True)
column.prop(sprops, "enable_source_id_attribute", text="Source ID Attributes")
else:
row = row.row(align=True)
row = row_other.row(align=True)
row.alignment = 'RIGHT'
row.prop(sprops, "enable_age_attribute", text="Age")
row.prop(sprops, "enable_lifetime_attribute", text="Life")
@@ -245,21 +208,28 @@ class FLIPFLUID_PT_DomainTypeFluidSurfacePanel(bpy.types.Panel):
def draw(self, context):
obj = vcu.get_active_object(context)
sprops = obj.flip_fluid.domain.surface
is_surface_mesh_generation_enabled = sprops.enable_surface_mesh_generation
column = self.layout.column(align=True)
column.prop(sprops, "enable_surface_mesh_generation")
#
# Surface Mesh Panel
#
box = self.layout.box()
row = box.row(align=True)
row.alert = not sprops.enable_surface_mesh_generation
row.prop(sprops, "surface_mesh_expanded",
icon="TRIA_DOWN" if sprops.surface_mesh_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Surface Mesh:")
header, body = box.panel("surface_mesh", default_closed=False)
if not sprops.surface_mesh_expanded:
row = header.row(align=True)
row.alert = not is_surface_mesh_generation_enabled
row.label(text="Surface Mesh:")
if body:
column = body.column(align=True)
column.prop(sprops, "subdivisions")
row = column.row(align=True)
if sprops.particle_scale < 0.999:
row.alert = True
row.prop(sprops, "particle_scale")
else:
info_text = "Subdivisions " + str(sprops.subdivisions) + " / "
info_text += "Scale " + "{:.2f}".format(sprops.particle_scale)
row = row.row(align=True)
@@ -268,71 +238,53 @@ class FLIPFLUID_PT_DomainTypeFluidSurfacePanel(bpy.types.Panel):
row.alert = True
row.label(text=info_text)
if sprops.surface_mesh_expanded:
column = box.column(align=True)
column.prop(sprops, "subdivisions")
row = column.row(align=True)
if sprops.particle_scale < 0.999:
row.alert = True
row.prop(sprops, "particle_scale")
object_collection = vcu.get_scene_collection()
if vcu.is_blender_28():
search_group = "all_objects"
else:
search_group = "objects"
#
# Meshing Volume Panel
#
box = self.layout.box()
row = box.row(align=True)
row.alert = not sprops.enable_surface_mesh_generation
row.prop(sprops, "meshing_volume_expanded",
icon="TRIA_DOWN" if sprops.meshing_volume_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
header, body = box.panel("meshing_volume", default_closed=True)
row = header.row(align=True)
row.alert = not is_surface_mesh_generation_enabled
row.label(text="Meshing Volume:")
if not sprops.meshing_volume_expanded:
info_text = ""
if sprops.meshing_volume_mode == "MESHING_VOLUME_MODE_DOMAIN":
info_text = "Domain Volume"
elif sprops.meshing_volume_mode == "MESHING_VOLUME_MODE_OBJECT":
info_text = "Object Volume"
row = row.row(align=True)
row.alignment = 'RIGHT'
row.label(text=info_text)
if sprops.meshing_volume_expanded:
row = box.row(align=True)
if body:
row = body.row(align=True)
row.prop(sprops, "meshing_volume_mode", expand=True)
column = box.column(align=True)
split = column.split(align=True)
column_left = split.column(align=True)
column_right = split.column(align=True)
column_right.enabled = sprops.meshing_volume_mode == "MESHING_VOLUME_MODE_OBJECT"
column_right.prop_search(sprops, "meshing_volume_object", object_collection, search_group, text="Object")
column_right.prop_search(sprops, "meshing_volume_object", vcu.get_scene_collection(), "all_objects", text="Object")
column_right.prop(sprops, "export_animated_meshing_volume_object")
box = self.layout.box()
row = box.row(align=True)
row.alert = not sprops.enable_surface_mesh_generation
row.prop(sprops, "meshing_against_boundary_expanded",
icon="TRIA_DOWN" if sprops.meshing_against_boundary_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Meshing Against Boundary:")
if not sprops.meshing_against_boundary_expanded:
else:
info_text = ""
if sprops.meshing_volume_mode == "MESHING_VOLUME_MODE_DOMAIN":
info_text = "Domain Volume"
elif sprops.meshing_volume_mode == "MESHING_VOLUME_MODE_OBJECT":
info_text = "Object Volume"
if sprops.meshing_volume_object is not None:
info_text += ": <" + sprops.meshing_volume_object.name + ">"
else:
info_text += ": None"
row = row.row(align=True)
row.alignment = 'RIGHT'
row.prop(sprops, "remove_mesh_near_domain", text="Remove")
row.label(text=info_text)
if sprops.meshing_against_boundary_expanded:
column = box.column(align=True)
#
# Meshing Volume Panel
#
box = self.layout.box()
header, body = box.panel("meshing_against_boundary", default_closed=True)
row = header.row(align=True)
row.alert = not is_surface_mesh_generation_enabled
row.label(text="Meshing Against Boundary:")
if body:
column = body.column(align=True)
column.prop(sprops, "remove_mesh_near_domain")
column = box.column(align=True)
column = body.column(align=True)
column.enabled = sprops.remove_mesh_near_domain
row = column.row(align=True)
row.prop(sprops, "remove_mesh_near_domain_sides", index=0, text="X ")
@@ -344,44 +296,31 @@ class FLIPFLUID_PT_DomainTypeFluidSurfacePanel(bpy.types.Panel):
row.prop(sprops, "remove_mesh_near_domain_sides", index=4, text="Z ")
row.prop(sprops, "remove_mesh_near_domain_sides", index=5, text="Z+")
column.prop(sprops, "remove_mesh_near_domain_distance")
else:
row = row.row(align=True)
row.alignment = 'RIGHT'
row.prop(sprops, "remove_mesh_near_domain", text="Remove")
#
# Meshing Against Obstacle Panel
#
box = self.layout.box()
row = box.row(align=True)
row.alert = not sprops.enable_surface_mesh_generation
row.prop(sprops, "meshing_against_obstacles_expanded",
icon="TRIA_DOWN" if sprops.meshing_against_obstacles_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Meshing Against Obstacles:")
header, body = box.panel("meshing_against_obstacles", default_closed=True)
if not sprops.meshing_against_obstacles_expanded:
row = header.row(align=True)
row.alert = not is_surface_mesh_generation_enabled
row.label(text="Meshing Against Obstacles:")
if body:
column = body.column(align=True)
column.prop(sprops, "enable_meshing_offset")
row = body.row(align=True)
row.enabled = sprops.enable_meshing_offset
row.prop(sprops, "obstacle_meshing_mode", expand=True)
else:
row = row.row(align=True)
row.alignment = 'RIGHT'
row.prop(sprops, "enable_meshing_offset", text="Enable ")
if sprops.meshing_against_obstacles_expanded:
column = box.column(align=True)
column.prop(sprops, "enable_meshing_offset")
row = box.row(align=True)
row.enabled = sprops.enable_meshing_offset
row.prop(sprops, "obstacle_meshing_mode", expand=True)
# Removed surface smoothing options. These are better set
# using a Blender smooth modifier.
"""
box = self.layout.box()
box.label(text="Smoothing:")
row = box.row(align=True)
row.prop(sprops, "smoothing_value")
row.prop(sprops, "smoothing_iterations")
"""
# Motion Blur is no longer supported
#column = self.layout.column(align=True)
#column.separator()
#column.prop(sprops, "generate_motion_blur_data")
_draw_fluid_surface_display_settings(self, context)
_draw_geometry_attributes_menu(self, context)
@@ -33,55 +33,22 @@ def _draw_geometry_attributes_menu(self, context):
wprops = dprops.whitewater
prefs = vcu.get_addon_preferences()
#
# Whitewater Attributes Panel
#
box = self.layout.box()
row = box.row(align=True)
row.prop(wprops, "geometry_attributes_expanded",
icon="TRIA_DOWN" if wprops.geometry_attributes_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Whitewater Attributes:")
header, body = box.panel("whitewater_geometry_attributes", default_closed=True)
if wprops.geometry_attributes_expanded:
if not prefs.is_extra_features_enabled():
warn_box = box.box()
warn_column = warn_box.column(align=True)
warn_column.enabled = True
warn_column.label(text=" This feature is affected by a current bug in Blender.", icon='ERROR')
warn_column.label(text=" The Extra Features option must be enabled in preferences")
warn_column.label(text=" to use this feature.")
warn_column.separator()
warn_column.prop(prefs, "enable_extra_features", text="Enable Extra Features in Preferences")
warn_column.separator()
warn_column.operator(
"wm.url_open",
text="Important Info and Limitations",
icon="WORLD"
).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Preferences-Menu-Settings#developer-tools"
return
column = box.column(align=True)
if not vcu.is_blender_31():
column.enabled = False
column.label(text="Geometry attribute features for whitewater are only available in", icon='ERROR')
column.label(text="Blender 3.1 or later", icon='ERROR')
return
column = box.column(align=True)
row = header.row(align=True)
row.label(text="Whitewater Attribute:")
if body:
column = body.column(align=True)
column.prop(wprops, "enable_velocity_vector_attribute")
column.prop(wprops, "enable_id_attribute")
column.prop(wprops, "enable_lifetime_attribute")
column.separator()
column.operator("flip_fluid_operators.helper_initialize_motion_blur")
else:
if not vcu.is_blender_31():
row = row.row(align=True)
row.enabled = False
row.alignment = 'RIGHT'
row.label(text="(Blender 3.1 or later required)")
return
if not prefs.is_extra_features_enabled():
return
row = row.row(align=True)
row.alignment = 'RIGHT'
row.prop(wprops, "enable_velocity_vector_attribute", text="Velocity")
@@ -118,29 +85,17 @@ class FLIPFLUID_PT_DomainTypeWhitewaterPanel(bpy.types.Panel):
column.prop(wprops, "enable_whitewater_simulation")
column.separator()
#
# Settings View Mode Panel
#
box = self.layout.box()
box.enabled = is_whitewater_enabled
header, body = box.panel("whitewater_settings_view_mode", default_closed=True)
column = box.column(align=True)
split = column.split(align=True)
column_left = split.column(align=True)
column_right = split.column(align=True)
row = column_left.row(align=True)
row.prop(wprops, "settings_view_mode_expanded",
icon="TRIA_DOWN" if wprops.settings_view_mode_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row = header.row(align=True)
row.label(text="Settings View Mode:")
if not wprops.settings_view_mode_expanded:
row = column_right.row(align=True)
row.alignment = 'RIGHT'
row.prop(wprops, "whitewater_ui_mode", expand=True)
if wprops.settings_view_mode_expanded:
column = box.column(align=True)
if body:
column = body.column(align=True)
row = column.row()
row.prop(wprops, "whitewater_ui_mode", expand=True)
@@ -149,18 +104,30 @@ class FLIPFLUID_PT_DomainTypeWhitewaterPanel(bpy.types.Panel):
column_right = split.column()
column_right.enabled = show_advanced_whitewater
column_right.prop(wprops, "highlight_advanced_settings")
else:
row = row.row(align=True)
row.alignment = 'RIGHT'
row.prop(wprops, "whitewater_ui_mode", expand=True)
#
# Whitewater Particle Types Panel
#
box = self.layout.box()
box.enabled = is_whitewater_enabled
row = box.row(align=True)
row.prop(wprops, "whitewater_simulation_particles_expanded",
icon="TRIA_DOWN" if wprops.whitewater_simulation_particles_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Whitewater Particles:")
header, body = box.panel("whitewater_simulation_particles", default_closed=True)
if not wprops.whitewater_simulation_particles_expanded:
row = header.row(align=True)
row.label(text="Whitewater Particle Types:")
if body:
column = body.column(align=True)
column.enabled = is_whitewater_enabled
row = column.row()
row.prop(wprops, "enable_foam")
row.prop(wprops, "enable_bubbles")
row.prop(wprops, "enable_spray")
row.prop(wprops, "enable_dust")
else:
info_text = ""
enabled_particles = []
if wprops.enable_foam:
@@ -183,48 +150,36 @@ class FLIPFLUID_PT_DomainTypeWhitewaterPanel(bpy.types.Panel):
row.alignment = 'RIGHT'
row.label(text=info_text)
if wprops.whitewater_simulation_particles_expanded:
column = box.column(align=True)
column.enabled = is_whitewater_enabled
row = column.row()
row.prop(wprops, "enable_foam")
row.prop(wprops, "enable_bubbles")
row.prop(wprops, "enable_spray")
row.prop(wprops, "enable_dust")
#
# Emitter Settings Panel
#
box = self.layout.box()
box.enabled = is_whitewater_enabled
row = box.row(align=True)
row.prop(wprops, "emitter_settings_expanded",
icon="TRIA_DOWN" if wprops.emitter_settings_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
header, body = box.panel("whitewater_emitter_settings", default_closed=False)
row = header.row(align=True)
row.label(text="Emitter Settings:")
if wprops.emitter_settings_expanded:
column = box.column(align=True)
if body:
column = body.column(align=True)
column.prop(wprops, "enable_whitewater_emission")
if show_advanced_whitewater:
column = box.column(align=True)
column = body.column(align=True)
column.alert = highlight_advanced
column.prop(wprops, "whitewater_emitter_generation_rate")
column = box.column(align=True)
column = body.column(align=True)
column.prop(wprops, "wavecrest_emission_rate")
column.prop(wprops, "turbulence_emission_rate")
column = column.column(align=True)
column.enabled = wprops.enable_dust
column.prop(wprops, "dust_emission_rate")
column = box.column(align=True)
column = body.column(align=True)
column.prop(wprops, "spray_emission_speed", slider=True)
if show_advanced_whitewater:
column = box.column(align=True)
column = body.column(align=True)
row = column.row(align=True)
row.prop(wprops.min_max_whitewater_energy_speed, "value_min")
row.prop(wprops.min_max_whitewater_energy_speed, "value_max")
@@ -239,35 +194,34 @@ class FLIPFLUID_PT_DomainTypeWhitewaterPanel(bpy.types.Panel):
row.prop(wprops.min_max_whitewater_turbulence, "value_min")
row.prop(wprops.min_max_whitewater_turbulence, "value_max")
else:
column = box.column()
column = body.column()
row = column.row(align=True)
row.prop(wprops.min_max_whitewater_energy_speed, "value_min")
row.prop(wprops.min_max_whitewater_energy_speed, "value_max")
column = box.column(align=True)
column = body.column(align=True)
column.prop(wprops, "max_whitewater_particles")
if show_advanced_whitewater:
column = box.column(align=True)
column = body.column(align=True)
column.alert = highlight_advanced
column.prop(wprops, "enable_whitewater_emission_near_boundary")
column = box.column(align=True)
column = body.column(align=True)
column.enabled = wprops.enable_dust
column.prop(wprops, "enable_dust_emission_near_boundary", text="Enable dust emission near domain floor")
column.prop(wprops, "enable_dust_emission_near_boundary", text="Enable Dust Emission Near Domain Floor")
#
# Particle Behavior Settings Panel
#
box = self.layout.box()
box.enabled = is_whitewater_enabled
row = box.row(align=True)
row.prop(wprops, "particle_settings_expanded",
icon="TRIA_DOWN" if wprops.particle_settings_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Particle Behavior Settings:")
header, body = box.panel("whitewater_particle_behavior_settings", default_closed=True)
if wprops.particle_settings_expanded:
column = box.column()
row = header.row(align=True)
row.label(text="Particle Behavior Settings:")
if body:
column = body.column()
column.label(text="Foam:")
row = column.row()
@@ -282,22 +236,22 @@ class FLIPFLUID_PT_DomainTypeWhitewaterPanel(bpy.types.Panel):
row.alert = highlight_advanced
row.prop(wprops, "foam_layer_offset", text="Offset", slider=True)
column = box.column(align=True)
column = body.column(align=True)
column.label(text="Bubble:")
column.prop(wprops, "bubble_drag_coefficient", text="Drag Coefficient", slider=True)
column.prop(wprops, "bubble_bouyancy_coefficient", text="Buoyancy Coefficient")
column = box.column(align=True)
column = body.column(align=True)
column.label(text="Spray:")
column.prop(wprops, "spray_drag_coefficient", text="Drag Coefficient", slider=True)
column = box.column(align=True)
column = body.column(align=True)
column.enabled = wprops.enable_dust
column.label(text="Dust:")
column.prop(wprops, "dust_drag_coefficient", text="Drag Coefficient", slider=True)
column.prop(wprops, "dust_bouyancy_coefficient", text="Buoyancy Coefficient")
column = box.column(align=True)
column = body.column(align=True)
split = column.split()
column = split.column(align=True)
column.label(text="Lifespan:")
@@ -314,28 +268,17 @@ class FLIPFLUID_PT_DomainTypeWhitewaterPanel(bpy.types.Panel):
column.enabled = wprops.enable_dust
column.prop(wprops, "dust_lifespan_modifier", text="Dust")
#
# Domain Boundary Collisions Panel
#
box = self.layout.box()
row = box.row(align=True)
row.prop(wprops, "boundary_behaviour_settings_expanded",
icon="TRIA_DOWN" if wprops.boundary_behaviour_settings_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
box.enabled = is_whitewater_enabled
header, body = box.panel("whitewater_boundary_behaviour_settings", default_closed=True)
row = header.row(align=True)
row.label(text="Domain Boundary Collisions:")
if not wprops.boundary_behaviour_settings_expanded:
info_text = ""
if wprops.whitewater_boundary_collisions_mode == 'BOUNDARY_COLLISIONS_MODE_INHERIT':
info_text = "Inherit"
elif wprops.whitewater_boundary_collisions_mode == 'BOUNDARY_COLLISIONS_MODE_CUSTOM':
info_text = "Custom"
row = row.row(align=True)
row.alignment = 'RIGHT'
row.label(text=info_text)
if wprops.boundary_behaviour_settings_expanded:
column = box.column()
if body:
column = body.column()
row = column.row(align=True)
row.prop(wprops, "whitewater_boundary_collisions_mode", expand=True)
@@ -417,26 +360,28 @@ class FLIPFLUID_PT_DomainTypeWhitewaterPanel(bpy.types.Panel):
row.alignment = 'LEFT'
row.prop(wprops, "dust_boundary_collisions", index=4, text="Z ")
row.prop(wprops, "dust_boundary_collisions", index=5, text="Z+")
else:
info_text = ""
if wprops.whitewater_boundary_collisions_mode == 'BOUNDARY_COLLISIONS_MODE_INHERIT':
info_text = "Inherit"
elif wprops.whitewater_boundary_collisions_mode == 'BOUNDARY_COLLISIONS_MODE_CUSTOM':
info_text = "Custom"
row = row.row(align=True)
row.alignment = 'RIGHT'
row.label(text=info_text)
#
# Obstacle Influence Settings Panel
#
box = self.layout.box()
box.enabled = is_whitewater_enabled
row = box.row(align=True)
row.prop(wprops, "obstacle_settings_expanded",
icon="TRIA_DOWN" if wprops.obstacle_settings_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
header, body = box.panel("whitewater_obstacle_influence_settings", default_closed=True)
row = header.row(align=True)
row.label(text="Obstacle Influence Settings:")
if wprops.obstacle_settings_expanded:
column = box.column(align=True)
# The following properties are probably set at reasonable values and
# are not needed by the user
"""
column.prop(wprops, "obstacle_influence_base_level", text="Base Level")
column.prop(wprops, "obstacle_influence_decay_rate", text="Decay Rate")
"""
if body:
column = body.column(align=True)
obstacle_objects = context.scene.flip_fluid.get_obstacle_objects()
indent_str = 5 * " "
@@ -48,31 +48,19 @@ class FLIPFLUID_PT_DomainTypeFluidWorldPanel(bpy.types.Panel):
wprops = obj.flip_fluid.domain.world
aprops = obj.flip_fluid.domain.advanced
#
# World Scale Panel
#
box = self.layout.box()
row = box.row(align=True)
row.prop(wprops, "world_scale_settings_expanded",
icon="TRIA_DOWN" if wprops.world_scale_settings_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
header, body = box.panel("world_scale_settings", default_closed=False)
row = header.row(align=True)
row.label(text="World Scale:")
if not wprops.world_scale_settings_expanded:
xdims, ydims, zdims = wprops.get_simulation_dimensions(context)
xdims_str = '{:.2f}'.format(round(xdims, 2)) + " m"
ydims_str = '{:.2f}'.format(round(ydims, 2)) + " m"
zdims_str = '{:.2f}'.format(round(zdims, 2)) + " m"
info_text = xdims_str + " x " + ydims_str + " x " + zdims_str
row = row.row(align=True)
row.alignment = 'RIGHT'
row.label(text=info_text)
if wprops.world_scale_settings_expanded:
row = box.row(align=True)
if body:
row = body.row(align=True)
row.prop(wprops, "world_scale_mode", expand=True)
column = box.column(align=True)
column = body.column(align=True)
split = column.split(align=True)
column_left = split.column()
column_right = split.column()
@@ -106,19 +94,27 @@ class FLIPFLUID_PT_DomainTypeFluidWorldPanel(bpy.types.Panel):
column_right.label(text=xdims_str)
column_right.label(text=ydims_str)
column_right.label(text=zdims_str)
else:
xdims, ydims, zdims = wprops.get_simulation_dimensions(context)
xdims_str = '{:.2f}'.format(round(xdims, 2)) + " m"
ydims_str = '{:.2f}'.format(round(ydims, 2)) + " m"
zdims_str = '{:.2f}'.format(round(zdims, 2)) + " m"
info_text = xdims_str + " x " + ydims_str + " x " + zdims_str
row = row.row(align=True)
row.alignment = 'RIGHT'
row.label(text=info_text)
#
# Gravity and Force Fields Panel
#
box = self.layout.box()
row = box.row(align=True)
row.prop(wprops, "force_field_settings_expanded",
icon="TRIA_DOWN" if wprops.force_field_settings_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
header, body = box.panel("gravity_and_force_field_settings", default_closed=True)
row = header.row(align=True)
row.label(text="Gravity and Force Fields:")
if wprops.force_field_settings_expanded:
subbox = box.box()
if body:
subbox = body.box()
subbox.label(text="Gravity:")
row = subbox.row(align=True)
row.prop(wprops, "gravity_type", expand=True)
@@ -154,7 +150,7 @@ class FLIPFLUID_PT_DomainTypeFluidWorldPanel(bpy.types.Panel):
column = subbox.column(align=True)
column.operator("flip_fluid_operators.make_zero_gravity")
subbox = box.box()
subbox = body.box()
subbox.label(text="Force Field Resolution:")
column = subbox.column(align=True)
row = column.row(align=True)
@@ -178,7 +174,7 @@ class FLIPFLUID_PT_DomainTypeFluidWorldPanel(bpy.types.Panel):
row.label(text="Grid resolution: ")
column_right.label(text=str(field_resolution))
subbox = box.box()
subbox = body.box()
subbox.label(text="Force Field Weights:")
column = subbox.column(align=True)
column.prop(wprops, "force_field_weight_fluid_particles", slider=True)
@@ -187,29 +183,21 @@ class FLIPFLUID_PT_DomainTypeFluidWorldPanel(bpy.types.Panel):
column.prop(wprops, "force_field_weight_whitewater_spray", slider=True)
column.prop(wprops, "force_field_weight_whitewater_dust", slider=True)
box = self.layout.box()
row = box.row(align=True)
row.prop(wprops, "viscosity_settings_expanded",
icon="TRIA_DOWN" if wprops.viscosity_settings_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
if not wprops.viscosity_settings_expanded:
row.prop(wprops, "enable_viscosity", text="")
row.label(text="Viscosity:")
#
# Viscosity Panel
#
is_variable_viscosity_enabled = attrprops.enable_viscosity_attribute
if not wprops.viscosity_settings_expanded:
if not is_variable_viscosity_enabled:
total_viscosity = wprops.viscosity * (10**(-wprops.viscosity_exponent))
total_viscosity_str = format_number_precision(self, total_viscosity)
row = row.row(align=True)
row.alignment = 'RIGHT'
row.enabled = wprops.enable_viscosity
row.label(text=total_viscosity_str)
if wprops.viscosity_settings_expanded:
column = box.column(align=True)
box = self.layout.box()
header, body = box.panel("viscosity_settings", default_closed=True)
row = header.row(align=True)
if not body:
row.prop(wprops, "enable_viscosity", text="")
row.label(text="Viscosity:")
if body:
column = body.column(align=True)
row = column.row(align=True)
row.prop(wprops, "enable_viscosity")
@@ -218,7 +206,7 @@ class FLIPFLUID_PT_DomainTypeFluidWorldPanel(bpy.types.Panel):
row.enabled = wprops.enable_viscosity
row.prop(attrprops, "enable_viscosity_attribute", text="Variable Viscosity")
column = box.column(align=True)
column = body.column(align=True)
column.enabled = wprops.enable_viscosity
if is_variable_viscosity_enabled:
@@ -236,29 +224,27 @@ class FLIPFLUID_PT_DomainTypeFluidWorldPanel(bpy.types.Panel):
total_viscosity = wprops.viscosity * (10**(-wprops.viscosity_exponent))
total_viscosity_str = "Total viscosity = " + format_number_precision(self, total_viscosity)
column.label(text=total_viscosity_str)
else:
if not is_variable_viscosity_enabled:
total_viscosity = wprops.viscosity * (10**(-wprops.viscosity_exponent))
total_viscosity_str = format_number_precision(self, total_viscosity)
row = row.row(align=True)
row.alignment = 'RIGHT'
row.enabled = wprops.enable_viscosity
row.label(text=total_viscosity_str)
#
# Surface Tension Panel
#
box = self.layout.box()
row = box.row(align=True)
row.prop(wprops, "surface_tension_settings_expanded",
icon="TRIA_DOWN" if wprops.surface_tension_settings_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
if not wprops.surface_tension_settings_expanded:
row.prop(wprops, "enable_surface_tension", text="")
header, body = box.panel("surface_tension_settings", default_closed=True)
row = header.row(align=True)
if not body:
row.prop(wprops, "enable_surface_tension", text="")
row.label(text="Surface Tension:")
if not wprops.surface_tension_settings_expanded:
total_surface_tension = wprops.get_surface_tension_value()
surface_tension_str = format_number_precision(self, total_surface_tension)
row = row.row(align=True)
row.alignment = 'RIGHT'
row.enabled = wprops.enable_surface_tension
row.alert = wprops.enable_surface_tension and wprops.minimum_surface_tension_substeps > aprops.min_max_time_steps_per_frame.value_max
row.label(text=surface_tension_str)
if wprops.surface_tension_settings_expanded:
column = box.column(align=True)
if body:
column = body.column(align=True)
split = column.split(align=True)
column_left = split.column(align=True)
column_left.prop(wprops, "enable_surface_tension")
@@ -292,21 +278,27 @@ class FLIPFLUID_PT_DomainTypeFluidWorldPanel(bpy.types.Panel):
row.alert = True
row.prop(wprops, "surface_tension_substeps_exceeded_tooltip", icon="QUESTION", emboss=False, text="")
row.label(text=" Warning: Too Many Substeps")
else:
total_surface_tension = wprops.get_surface_tension_value()
surface_tension_str = format_number_precision(self, total_surface_tension)
row = row.row(align=True)
row.alignment = 'RIGHT'
row.enabled = wprops.enable_surface_tension
row.alert = wprops.enable_surface_tension and wprops.minimum_surface_tension_substeps > aprops.min_max_time_steps_per_frame.value_max
row.label(text=surface_tension_str)
#
# Sheeting Effects Panel
#
box = self.layout.box()
row = box.row(align=True)
row.prop(wprops, "sheeting_settings_expanded",
icon="TRIA_DOWN" if wprops.sheeting_settings_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
if not wprops.sheeting_settings_expanded:
row.prop(wprops, "enable_sheet_seeding", text="")
row.label(text="Sheeting Effects:")
header, body = box.panel("sheeting_effects_settings", default_closed=True)
if wprops.sheeting_settings_expanded:
box.label(text="Sheeting Effects:")
column = box.column(align=True)
row = header.row(align=True)
if not body:
row.prop(wprops, "enable_sheet_seeding", text="")
row.label(text="Sheeting Effects:")
if body:
column = body.column(align=True)
split = column.split(align=True)
column_left = split.column(align=True)
column_left.prop(wprops, "enable_sheet_seeding")
@@ -328,42 +320,54 @@ class FLIPFLUID_PT_DomainTypeFluidWorldPanel(bpy.types.Panel):
pgroup = ob.flip_fluid.get_property_group()
column_left.label(text=ob.name, icon="OBJECT_DATA")
column_right.prop(pgroup, "sheeting_strength", text="Strength Scale")
#
# Variable Density Panel
#
box = self.layout.box()
row = box.row(align=True)
row.prop(wprops, "friction_settings_expanded",
icon="TRIA_DOWN" if wprops.friction_settings_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
header, body = box.panel("variable_density_settings", default_closed=True)
row = header.row(align=True)
if not body:
row.prop(wprops, "enable_density_attribute", text="")
row.label(text="Variable Density:")
if body:
column = body.column(align=True)
column.prop(wprops, "enable_density_attribute")
column = body.column(align=True)
column.enabled = wprops.enable_density_attribute
column.label(text="Variable density values can be set in the", icon='INFO')
column.label(text="Fluid or Inflow physics properties menu", icon='INFO')
#
# Friction Panel
#
box = self.layout.box()
header, body = box.panel("friction_settings", default_closed=True)
row = header.row(align=True)
row.label(text="Friction:")
if not wprops.friction_settings_expanded:
row = row.row(align=True)
row.alignment = 'RIGHT'
row.label(text="Boundary Friction ")
row.prop(wprops, "boundary_friction", text="")
if wprops.friction_settings_expanded:
column = box.column()
if body:
column = body.column()
split = column.split(align=True)
column_left = split.column()
column_left.label(text="Boundary Friction:")
column_right = split.column()
column_right.prop(wprops, "boundary_friction", text="")
row = box.row(align=True)
row.prop(wprops, "obstacle_friction_expanded",
icon="TRIA_DOWN" if wprops.obstacle_friction_expanded else "TRIA_RIGHT",
icon_only=True,
emboss=False
)
row.label(text="Obstacle Friction:")
#
# Obstacle Friction Panel
#
box = body.box()
header_obstacle_friction, body_obstacle_friction = box.panel("obstacle_friction_settings", default_closed=True)
if wprops.obstacle_friction_expanded:
row_obstacle_friction = header_obstacle_friction.row(align=True)
row_obstacle_friction.label(text="Obstacle Friction:")
if body_obstacle_friction:
obstacle_objects = context.scene.flip_fluid.get_obstacle_objects()
column = box.column(align=True)
column = body_obstacle_friction.column(align=True)
indent_str = 5 * " "
if len(obstacle_objects) == 0:
column.label(text=indent_str + "No obstacle objects found...")
@@ -375,6 +379,11 @@ class FLIPFLUID_PT_DomainTypeFluidWorldPanel(bpy.types.Panel):
pgroup = ob.flip_fluid.get_property_group()
column_left.label(text=ob.name, icon="OBJECT_DATA")
column_right.prop(pgroup, "friction")
else:
row = row.row(align=True)
row.alignment = 'RIGHT'
row.label(text="Boundary Friction ")
row.prop(wprops, "boundary_friction", text="")
def register():
@@ -104,10 +104,7 @@ class FLIPFLUID_PT_FluidTypePanel(bpy.types.Panel):
column_left.prop(fluid_props, "initial_speed")
target_collection = vcu.get_scene_collection()
if vcu.is_blender_28():
search_group = "all_objects"
else:
search_group = "objects"
search_group = "all_objects"
column_right = split.column(align=True)
column_right.label(text="Target Object:")
@@ -137,80 +134,91 @@ class FLIPFLUID_PT_FluidTypePanel(bpy.types.Panel):
box = self.layout.box()
box.label(text="Geometry Attributes:")
column = box.column(align=True)
if vcu.is_blender_293():
is_color_attribute_enabled = dprops is not None and (dprops.surface.enable_color_attribute or
dprops.particles.enable_fluid_particle_color_attribute)
show_color = dprops is not None and is_color_attribute_enabled
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_color
column_left.prop(fluid_props, "color")
column_right = split.column(align=True)
column_right.label(text="")
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_color:
row.operator("flip_fluid_operators.enable_color_attribute_tooltip",
text="Enable Color Attribute", icon="PLUS", emboss=False)
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
is_color_attribute_enabled = dprops is not None and (dprops.surface.enable_color_attribute or
dprops.particles.enable_fluid_particle_color_attribute)
show_color = dprops is not None and is_color_attribute_enabled
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_color
column_left.prop(fluid_props, "color")
column_right = split.column(align=True)
column_right.label(text="")
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_color:
row.operator("flip_fluid_operators.enable_color_attribute_tooltip",
text="Enable Color Attribute", icon="PLUS", emboss=False)
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
show_viscosity = dprops is not None and dprops.surface.enable_viscosity_attribute
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_viscosity
column_left.prop(fluid_props, "viscosity")
column_right = split.column(align=True)
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_viscosity:
row.operator("flip_fluid_operators.enable_viscosity_attribute_tooltip",
text="Enable Viscosity Attribute", icon="PLUS", emboss=False)
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
show_viscosity = dprops is not None and dprops.world.enable_viscosity and dprops.surface.enable_viscosity_attribute
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_viscosity
column_left.prop(fluid_props, "viscosity")
column_right = split.column(align=True)
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_viscosity:
row.operator("flip_fluid_operators.enable_viscosity_attribute_tooltip",
text="Enable Viscosity Attribute", icon="PLUS", emboss=False)
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
is_lifetime_attribute_enabled = dprops is not None and (dprops.surface.enable_lifetime_attribute or
dprops.particles.enable_fluid_particle_lifetime_attribute)
show_lifetime = dprops is not None and is_lifetime_attribute_enabled
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_lifetime
column_left.prop(fluid_props, "lifetime")
column_right = split.column(align=True)
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_lifetime:
row.operator("flip_fluid_operators.enable_lifetime_attribute_tooltip",
text="Enable Lifetime Attribute", icon="PLUS", emboss=False)
elif dprops is not None:
row.alignment = 'EXPAND'
row.prop(fluid_props, "lifetime_variance", text="Variance")
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
show_density = dprops is not None and dprops.world.enable_density_attribute
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_density
column_left.prop(fluid_props, "density")
column_right = split.column(align=True)
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_density:
row.operator("flip_fluid_operators.enable_density_attribute_tooltip",
text="Enable Density Attribute", icon="PLUS", emboss=False)
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
is_source_id_attribute_enabled = dprops is not None and (dprops.surface.enable_source_id_attribute or
dprops.particles.enable_fluid_particle_source_id_attribute)
show_source_id = dprops is not None and is_source_id_attribute_enabled
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_source_id
column_left.prop(fluid_props, "source_id")
column_right = split.column(align=True)
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_source_id:
row.operator("flip_fluid_operators.enable_source_id_attribute_tooltip",
text="Enable Source ID Attribute", icon="PLUS", emboss=False)
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
else:
column.enabled = False
column.label(text="Geometry attribute features are only available in", icon='ERROR')
column.label(text="Blender 2.93 or later", icon='ERROR')
is_lifetime_attribute_enabled = dprops is not None and (dprops.surface.enable_lifetime_attribute or
dprops.particles.enable_fluid_particle_lifetime_attribute)
show_lifetime = dprops is not None and is_lifetime_attribute_enabled
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_lifetime
column_left.prop(fluid_props, "lifetime")
column_right = split.column(align=True)
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_lifetime:
row.operator("flip_fluid_operators.enable_lifetime_attribute_tooltip",
text="Enable Lifetime Attribute", icon="PLUS", emboss=False)
elif dprops is not None:
row.alignment = 'EXPAND'
row.prop(fluid_props, "lifetime_variance", text="Variance")
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
is_source_id_attribute_enabled = dprops is not None and (dprops.surface.enable_source_id_attribute or
dprops.particles.enable_fluid_particle_source_id_attribute)
show_source_id = dprops is not None and is_source_id_attribute_enabled
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_source_id
column_left.prop(fluid_props, "source_id")
column_right = split.column(align=True)
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_source_id:
row.operator("flip_fluid_operators.enable_source_id_attribute_tooltip",
text="Enable Source ID Attribute", icon="PLUS", emboss=False)
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
box = self.layout.box()
box.label(text="Mesh Data Export:")
@@ -184,7 +184,7 @@ class FLIPFLUID_PT_ForceFieldTypePanel(bpy.types.Panel):
self.layout.separator()
box = self.layout.box()
box.label(text="Antigravity")
box.label(text="Antigravity:")
column = box.column(align=True)
if force_field_props.force_field_type == 'FORCE_FIELD_TYPE_POINT':
@@ -199,6 +199,18 @@ class FLIPFLUID_PT_ForceFieldTypePanel(bpy.types.Panel):
elif force_field_props.force_field_type == 'FORCE_FIELD_TYPE_CURVE':
column.prop(force_field_props, "gravity_scale_curve", slider=True)
column.prop(force_field_props, "gravity_scale_width_curve", text="Width", slider=True)
dprops = context.scene.flip_fluid.get_domain_properties()
if dprops is not None:
box = self.layout.box()
box.label(text="Global Force Field Weights:")
column = box.column(align=True)
column.prop(dprops.world, "force_field_weight_fluid_particles", slider=True)
column.prop(dprops.world, "force_field_weight_whitewater_foam", slider=True)
column.prop(dprops.world, "force_field_weight_whitewater_bubble", slider=True)
column.prop(dprops.world, "force_field_weight_whitewater_spray", slider=True)
column.prop(dprops.world, "force_field_weight_whitewater_dust", slider=True)
box = self.layout.box()
box.label(text="Mesh Data Export:")
File diff suppressed because it is too large Load Diff
@@ -97,10 +97,7 @@ class FLIPFLUID_PT_InflowTypePanel(bpy.types.Panel):
column_left.prop(inflow_props, "inflow_speed")
target_collection = vcu.get_scene_collection()
if vcu.is_blender_28():
search_group = "all_objects"
else:
search_group = "objects"
search_group = "all_objects"
column_right = split.column(align=True)
column_right.label(text="Target Object:")
@@ -132,80 +129,91 @@ class FLIPFLUID_PT_InflowTypePanel(bpy.types.Panel):
box = self.layout.box()
box.label(text="Geometry Attributes:")
column = box.column(align=True)
if vcu.is_blender_293():
is_color_attribute_enabled = dprops is not None and (dprops.surface.enable_color_attribute or
dprops.particles.enable_fluid_particle_color_attribute)
show_color = dprops is not None and is_color_attribute_enabled
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_color
column_left.prop(inflow_props, "color")
column_right = split.column(align=True)
column_right.label(text="")
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_color:
row.operator("flip_fluid_operators.enable_color_attribute_tooltip",
text="Enable Color Attribute", icon="PLUS", emboss=False)
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
is_color_attribute_enabled = dprops is not None and (dprops.surface.enable_color_attribute or
dprops.particles.enable_fluid_particle_color_attribute)
show_color = dprops is not None and is_color_attribute_enabled
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_color
column_left.prop(inflow_props, "color")
column_right = split.column(align=True)
column_right.label(text="")
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_color:
row.operator("flip_fluid_operators.enable_color_attribute_tooltip",
text="Enable Color Attribute", icon="PLUS", emboss=False)
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
show_viscosity = dprops is not None and dprops.surface.enable_viscosity_attribute
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_viscosity
column_left.prop(inflow_props, "viscosity")
column_right = split.column(align=True)
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_viscosity:
row.operator("flip_fluid_operators.enable_viscosity_attribute_tooltip",
text="Enable Viscosity Attribute", icon="PLUS", emboss=False)
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
show_viscosity = dprops is not None and dprops.world.enable_viscosity and dprops.surface.enable_viscosity_attribute
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_viscosity
column_left.prop(inflow_props, "viscosity")
column_right = split.column(align=True)
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_viscosity:
row.operator("flip_fluid_operators.enable_viscosity_attribute_tooltip",
text="Enable Viscosity Attribute", icon="PLUS", emboss=False)
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
is_lifetime_attribute_enabled = dprops is not None and (dprops.surface.enable_lifetime_attribute or
dprops.particles.enable_fluid_particle_lifetime_attribute)
show_lifetime = dprops is not None and is_lifetime_attribute_enabled
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_lifetime
column_left.prop(inflow_props, "lifetime")
column_right = split.column(align=True)
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_lifetime:
row.operator("flip_fluid_operators.enable_lifetime_attribute_tooltip",
text="Enable Lifetime Attribute", icon="PLUS", emboss=False)
elif dprops is not None:
row.alignment = 'EXPAND'
row.prop(inflow_props, "lifetime_variance", text="Variance")
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
show_density = dprops is not None and dprops.world.enable_density_attribute
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_density
column_left.prop(inflow_props, "density")
column_right = split.column(align=True)
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_density:
row.operator("flip_fluid_operators.enable_density_attribute_tooltip",
text="Enable Density Attribute", icon="PLUS", emboss=False)
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
is_source_id_attribute_enabled = dprops is not None and (dprops.surface.enable_source_id_attribute or
dprops.particles.enable_fluid_particle_source_id_attribute)
show_source_id = dprops is not None and is_source_id_attribute_enabled
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_source_id
column_left.prop(inflow_props, "source_id")
column_right = split.column(align=True)
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_source_id:
row.operator("flip_fluid_operators.enable_source_id_attribute_tooltip",
text="Enable Source ID Attribute", icon="PLUS", emboss=False)
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
else:
column.enabled = False
column.label(text="Geometry attribute features are only available in", icon='ERROR')
column.label(text="Blender 2.93 or later", icon='ERROR')
is_lifetime_attribute_enabled = dprops is not None and (dprops.surface.enable_lifetime_attribute or
dprops.particles.enable_fluid_particle_lifetime_attribute)
show_lifetime = dprops is not None and is_lifetime_attribute_enabled
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_lifetime
column_left.prop(inflow_props, "lifetime")
column_right = split.column(align=True)
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_lifetime:
row.operator("flip_fluid_operators.enable_lifetime_attribute_tooltip",
text="Enable Lifetime Attribute", icon="PLUS", emboss=False)
elif dprops is not None:
row.alignment = 'EXPAND'
row.prop(inflow_props, "lifetime_variance", text="Variance")
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
is_source_id_attribute_enabled = dprops is not None and (dprops.surface.enable_source_id_attribute or
dprops.particles.enable_fluid_particle_source_id_attribute)
show_source_id = dprops is not None and is_source_id_attribute_enabled
split = column.split(align=True)
column_left = split.column(align=True)
column_left.enabled = show_source_id
column_left.prop(inflow_props, "source_id")
column_right = split.column(align=True)
row = column_right.row(align=True)
row.alignment = 'LEFT'
if dprops is not None and not show_source_id:
row.operator("flip_fluid_operators.enable_source_id_attribute_tooltip",
text="Enable Source ID Attribute", icon="PLUS", emboss=False)
if dprops is None:
row.label(text="Domain required for this option")
column.separator()
box = self.layout.box()
box.label(text="Mesh Data Export:")
@@ -29,8 +29,6 @@ from .. import render
def frame_change_post_apply_T71908_workaround(context, depsgraph=None):
if not render.is_rendering():
return
if not vcu.is_blender_281():
return
dprops = context.scene.flip_fluid.get_domain_properties()
if dprops is None:
@@ -76,24 +74,97 @@ def frame_change_post_apply_T71908_workaround(context, depsgraph=None):
# Also apply to other FF_GeometryNodes inputs in case the user wants to keyframe these values.
input_name_list_surface = [
"Input_4", # Motion Blur Scale
"Input_6", # Enable Motion Blur
"Socket_0", # Blur Velocity For Fading
"Socket_5", # Shade Smooth Surface
"Socket_6", # Blur Iterations
"Input_6", # Enable Motion Blur
"Input_4", # Motion Blur Scale
"Socket_8", # Apply Simulation Time Scale
"Socket_9", # Apply Simulation World Scale
"Socket_5", # Shade Smooth Surface
"Socket_11", # Remove Mesh Near Domain Boundary
"Socket_12", # X-
"Socket_13", # Y-
"Socket_14", # Z-
"Socket_15", # X+
"Socket_16", # Y+
"Socket_17", # Z+
"Socket_18", # Distance
"Socket_20", # Flatten Mesh Near Domain Boundary
"Socket_21", # Water Level Mode
"Socket_22", # Water Level
"Socket_24", # Flattened Width
"Socket_25", # Transition Width
"Socket_27", # Store Displacement Attribute
"Socket_26", # Store Transition Mask Attribute
"Socket_0", # Blur Velocity For Fading
"Socket_6", # Blur Iterations
]
input_name_list_particles = [
"Input_4", # Motion Blur Scale
"Input_6", # Particle Scale
"Input_8", # Enable Motion Blur
"Input_9", # Enable Point Cloud
"Input_10", # Enable Instancing
"Socket_0", # Fading Strength
"Socket_1", # Fading Width
"Socket_2", # Particle Scale Random
"Socket_4", # Fading Density
"Socket_9", # Shade Smooth Instancing
input_name_list_fluid_particles = [
"Socket_16", # Apply Material
"Input_8", # Enable Motion Blur
"Input_4", # Motion Blur Scale
"Socket_47", # Apply Simulation Time Scale
"Socket_48", # Apply Simulation World Scale
"Socket_12", # Particle Display Mode
"Input_6", # Particle Scale
"Socket_11", # Particle Scale Multiplier
"Socket_2", # Particle Scale Random
"Socket_21", # Random Bias
"Socket_14", # Instancing Mode
"Socket_18", # Randomize Instance Rotation
"Socket_19", # Align Instance to Velocity
"Socket_10", # Shade Smooth Instances
"Socket_17", # Realize Instances
"Socket_51", # Matched Flattened Surface Displacement
"Socket_30", # Age Based Particle Scaling
"Socket_31", # Starting Scale Factor
"Socket_32", # Scaling Duration (Age)
"Socket_33", # Age Offset
"Socket_34", # Store Age Scaling Transition Attribute
"Socket_24", # Lifetime Based Particle Scaling
"Socket_23", # Final Scale Factor
"Socket_25", # Scaling Duration (Lifetime)
"Socket_26", # Lifetime Offset
"Socket_28", # Store Lifetime Scaling Transition Attribute
"Socket_36", # Filter Particle by Source ID
"Socket_37", # Source ID 0
"Socket_38", # Source ID 1
"Socket_39", # Source ID 2
"Socket_40", # Source ID 3
"Socket_41", # Source ID 4
"Socket_42", # Source ID 5
"Socket_43", # Source ID 6
"Socket_44", # Source ID 7
"Socket_45", # Source ID 8
"Socket_1", # Fading Width
"Socket_0", # Fading Strength
"Socket_4", # Fading Density
]
input_name_list_whitewater = [
"Socket_16", # Apply Material
"Input_8", # Enable Motion Blur
"Input_4", # Motion Blur Scale
"Socket_30", # Apply Simulation Time Scale
"Socket_31", # Apply Simulation World Scale
"Socket_12", # Particle Display Mode
"Input_6", # Particle Scale
"Socket_11", # Particle Scale Multiplier
"Socket_2", # Particle Scale Random
"Socket_21", # Random Bias
"Socket_14", # Instancing Mode
"Socket_18", # Randomize Instance Rotation
"Socket_19", # Align Instance to Velocity
"Socket_10", # Shade Smooth Instances
"Socket_17", # Realize Instances
"Socket_34", # Matched Flattened Surface Displacement
"Socket_24", # Lifetime Based Particle Scaling
"Socket_23", # Final Scale Factor
"Socket_25", # Scaling Duration (Lifetime)
"Socket_26", # Lifetime Offset
"Socket_28", # Store Lifetime Scaling Transition Attribute
"Socket_1", # Fading Width
"Socket_0", # Fading Strength
"Socket_4", # Fading Density
]
for obj in cache_objects:
@@ -103,8 +174,10 @@ def frame_change_post_apply_T71908_workaround(context, depsgraph=None):
mod_name = obj.modifiers[i].name
if mod_name.startswith("FF_GeometryNodesSurface"):
input_name_list = input_name_list_surface
elif mod_name.startswith("FF_GeometryNodesFluidParticles") or mod_name.startswith("FF_GeometryNodesWhitewater"):
input_name_list = input_name_list_particles
elif mod_name.startswith("FF_GeometryNodesFluidParticles"):
input_name_list = input_name_list_fluid_particles
elif mod_name.startswith("FF_GeometryNodesWhitewater"):
input_name_list = input_name_list_whitewater
else:
continue
@@ -153,20 +226,12 @@ def load_post_update_cycles_visibility_forward_compatibility_from_blender_3():
def set_cycles_ray_visibility(bl_object, is_enabled):
# Cycles may not be enabled in the user's preferences
try:
if vcu.is_blender_30():
bl_object.visible_camera = is_enabled
bl_object.visible_diffuse = is_enabled
bl_object.visible_glossy = is_enabled
bl_object.visible_transmission = is_enabled
bl_object.visible_volume_scatter = is_enabled
bl_object.visible_shadow = is_enabled
else:
bl_object.cycles_visibility.camera = is_enabled
bl_object.cycles_visibility.transmission = is_enabled
bl_object.cycles_visibility.diffuse = is_enabled
bl_object.cycles_visibility.scatter = is_enabled
bl_object.cycles_visibility.glossy = is_enabled
bl_object.cycles_visibility.shadow = is_enabled
bl_object.visible_camera = is_enabled
bl_object.visible_diffuse = is_enabled
bl_object.visible_glossy = is_enabled
bl_object.visible_transmission = is_enabled
bl_object.visible_volume_scatter = is_enabled
bl_object.visible_shadow = is_enabled
except:
pass
@@ -394,10 +459,10 @@ def is_keyframed_hide_render_issue_relevant(scene):
if not obj.animation_data:
continue
anim_data = obj.animation_data
if not anim_data.action or not anim_data.action.fcurves:
if not anim_data.action or not anim_data.action.layers[0].strips[0].channelbag(anim_data.action.slots[0]).fcurves:
continue
for fcurve in anim_data.action.fcurves:
for fcurve in anim_data.action.layers[0].strips[0].channelbag(anim_data.action.slots[0]).fcurves:
if fcurve.data_path == "hide_render":
is_relevant = True
break

Some files were not shown because too many files have changed in this diff Show More