2025-12-01
This commit is contained in:
+547
@@ -0,0 +1,547 @@
|
||||
import bpy, os, time, sys
|
||||
|
||||
|
||||
def check_cache_exists():
|
||||
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:
|
||||
print("\nError: Simulation cache does not exist. Nothing to export. Exiting.")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def initialize_simulation_mesh_selection():
|
||||
dprops = bpy.context.scene.flip_fluid.get_domain_properties()
|
||||
hprops = bpy.context.scene.flip_fluid_helper
|
||||
|
||||
print("Searching for simulation meshes:")
|
||||
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
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)
|
||||
num_export_meshes += 1
|
||||
print(" FOUND <" + bl_surface.name + ">")
|
||||
else:
|
||||
print(" NOT FOUND")
|
||||
else:
|
||||
dprops.mesh_cache.disable_simulation_mesh_load('SURFACE')
|
||||
print("Fluid surface export disabled, skipping...")
|
||||
|
||||
if hprops.alembic_export_fluid_particles:
|
||||
print("Searching for fluid particles mesh...", end="")
|
||||
bl_fluid_particles = dprops.mesh_cache.particles.get_cache_object()
|
||||
if bl_fluid_particles is not None:
|
||||
bl_fluid_particles.select_set(True)
|
||||
num_export_meshes += 1
|
||||
print(" FOUND <" + bl_fluid_particles.name + ">")
|
||||
else:
|
||||
print(" NOT FOUND")
|
||||
else:
|
||||
dprops.mesh_cache.disable_simulation_mesh_load('FLUID_PARTICLES')
|
||||
print("Fluid particles export disabled, skipping...")
|
||||
|
||||
if hprops.alembic_export_foam:
|
||||
print("Searching for whitewater foam mesh...", end="")
|
||||
bl_foam = dprops.mesh_cache.foam.get_cache_object()
|
||||
if bl_foam is not None:
|
||||
bl_foam.select_set(True)
|
||||
num_export_meshes += 1
|
||||
print(" FOUND <" + bl_foam.name + ">")
|
||||
else:
|
||||
print(" NOT FOUND")
|
||||
else:
|
||||
dprops.mesh_cache.disable_simulation_mesh_load('FOAM')
|
||||
print("Whitewater foam export disabled, skipping...")
|
||||
|
||||
if hprops.alembic_export_bubble:
|
||||
print("Searching for whitewater bubble mesh...", end="")
|
||||
bl_bubble = dprops.mesh_cache.bubble.get_cache_object()
|
||||
if bl_bubble is not None:
|
||||
bl_bubble.select_set(True)
|
||||
num_export_meshes += 1
|
||||
print(" FOUND <" + bl_bubble.name + ">")
|
||||
else:
|
||||
print(" NOT FOUND")
|
||||
else:
|
||||
dprops.mesh_cache.disable_simulation_mesh_load('BUBBLE')
|
||||
print("Whitewater bubble export disabled, skipping...")
|
||||
|
||||
if hprops.alembic_export_spray:
|
||||
print("Searching for whitewater spray mesh...", end="")
|
||||
bl_spray = dprops.mesh_cache.spray.get_cache_object()
|
||||
if bl_spray is not None:
|
||||
bl_spray.select_set(True)
|
||||
num_export_meshes += 1
|
||||
print(" FOUND <" + bl_spray.name + ">")
|
||||
else:
|
||||
print(" NOT FOUND")
|
||||
else:
|
||||
dprops.mesh_cache.disable_simulation_mesh_load('SPRAY')
|
||||
print("Whitewater spray export disabled, skipping...")
|
||||
|
||||
if hprops.alembic_export_dust:
|
||||
print("Searching for whitewater dust mesh...", end="")
|
||||
bl_dust = dprops.mesh_cache.dust.get_cache_object()
|
||||
if bl_dust is not None:
|
||||
bl_dust.select_set(True)
|
||||
num_export_meshes += 1
|
||||
print(" FOUND <" + bl_dust.name + ">")
|
||||
else:
|
||||
print(" NOT FOUND")
|
||||
else:
|
||||
dprops.mesh_cache.disable_simulation_mesh_load('DUST')
|
||||
print("Whitewater dust export disabled, skipping...")
|
||||
|
||||
dprops.mesh_cache.disable_simulation_mesh_load('OBSTACLE_DEBUG')
|
||||
dprops.mesh_cache.disable_simulation_mesh_load('PARTICLE_DEBUG')
|
||||
dprops.mesh_cache.disable_simulation_mesh_load('FORCE_FIELD_DEBUG')
|
||||
|
||||
print("Finished searching for simulation meshes.")
|
||||
|
||||
if num_export_meshes == 0:
|
||||
print("\nError: Nothing to export. Exiting.")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def add_geometry_node_modifier(target_object, resource_filepath, resource_name):
|
||||
for mod in target_object.modifiers:
|
||||
if mod.type == 'NODES' and mod.name == resource_name:
|
||||
# Already added
|
||||
return mod
|
||||
|
||||
node_group = bpy.data.node_groups.get(resource_name)
|
||||
if node_group is None:
|
||||
is_resource_found = False
|
||||
with bpy.data.libraries.load(resource_filepath) as (data_from, data_to):
|
||||
resource = [name for name in data_from.node_groups if name == resource_name]
|
||||
if resource:
|
||||
is_resource_found = True
|
||||
data_to.node_groups = resource
|
||||
|
||||
if not is_resource_found:
|
||||
return None
|
||||
|
||||
imported_resource_name = data_to.node_groups[0].name
|
||||
else:
|
||||
# already imported
|
||||
imported_resource_name = node_group.name
|
||||
|
||||
gn_modifier = target_object.modifiers.new(resource_name, type="NODES")
|
||||
gn_modifier.node_group = bpy.data.node_groups.get(imported_resource_name)
|
||||
return gn_modifier
|
||||
|
||||
|
||||
def get_geomety_nodes_motion_blur_scale(bl_object):
|
||||
gn_modifier = None
|
||||
for mod in bl_object.modifiers:
|
||||
if mod.type == 'NODES' and mod.name.startswith("FF_GeometryNodes"):
|
||||
gn_modifier = mod
|
||||
break
|
||||
|
||||
if gn_modifier is not None:
|
||||
try:
|
||||
# Depending on FLIP Fluids version, the GN set up may not
|
||||
# have an Input_4
|
||||
return gn_modifier["Input_4"]
|
||||
except:
|
||||
return 1.0
|
||||
return 1.0
|
||||
|
||||
|
||||
def set_geometry_nodes_alembic_velocity_export_motion_blur_scale(bl_object, scale):
|
||||
gn_modifier = None
|
||||
for mod in bl_object.modifiers:
|
||||
if mod.type == 'NODES' and mod.name.startswith("FF_AlembicVelocityExport"):
|
||||
gn_modifier = mod
|
||||
break
|
||||
|
||||
if gn_modifier is not None:
|
||||
try:
|
||||
# Depending on FLIP Fluids version, the GN set up may not
|
||||
# have an Input_4
|
||||
gn_modifier["Input_4"] = scale
|
||||
return scale
|
||||
except:
|
||||
return 1.0
|
||||
return 1.0
|
||||
|
||||
|
||||
def initialize_velocity_export_and_attributes():
|
||||
dprops = bpy.context.scene.flip_fluid.get_domain_properties()
|
||||
hprops = bpy.context.scene.flip_fluid_helper
|
||||
|
||||
surface_motion_blur_scale = 1.0
|
||||
fluid_particles_motion_blur_scale = 1.0
|
||||
foam_motion_blur_scale = 1.0
|
||||
bubble_motion_blur_scale = 1.0
|
||||
spray_motion_blur_scale = 1.0
|
||||
dust_motion_blur_scale = 1.0
|
||||
|
||||
bl_surface = dprops.mesh_cache.surface.get_cache_object()
|
||||
if bl_surface is not None:
|
||||
surface_motion_blur_scale = get_geomety_nodes_motion_blur_scale(bl_surface)
|
||||
bl_fluid_particles = dprops.mesh_cache.particles.get_cache_object()
|
||||
if bl_fluid_particles is not None:
|
||||
fluid_particles_motion_blur_scale = get_geomety_nodes_motion_blur_scale(bl_fluid_particles)
|
||||
bl_foam = dprops.mesh_cache.foam.get_cache_object()
|
||||
if bl_foam is not None:
|
||||
foam_motion_blur_scale = get_geomety_nodes_motion_blur_scale(bl_foam)
|
||||
bl_bubble = dprops.mesh_cache.bubble.get_cache_object()
|
||||
if bl_bubble is not None:
|
||||
bubble_motion_blur_scale = get_geomety_nodes_motion_blur_scale(bl_bubble)
|
||||
bl_spray = dprops.mesh_cache.spray.get_cache_object()
|
||||
if bl_spray is not None:
|
||||
spray_motion_blur_scale = get_geomety_nodes_motion_blur_scale(bl_spray)
|
||||
bl_dust = dprops.mesh_cache.dust.get_cache_object()
|
||||
if bl_dust is not None:
|
||||
dust_motion_blur_scale = get_geomety_nodes_motion_blur_scale(bl_dust)
|
||||
|
||||
print("\nRemoving motion blur render setup:")
|
||||
bpy.ops.flip_fluid_operators.helper_remove_motion_blur('INVOKE_DEFAULT', resource_prefix="FF_GeometryNodes")
|
||||
print("Finished removing 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")
|
||||
|
||||
bl_surface = dprops.mesh_cache.surface.get_cache_object()
|
||||
if bl_surface is not None:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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.")
|
||||
|
||||
print("\nOptimizing attribute loading:")
|
||||
if hprops.alembic_export_velocity:
|
||||
if not dprops.surface.enable_velocity_vector_attribute:
|
||||
dprops.surface.enable_velocity_vector_attribute = True
|
||||
print("Enabled fluid surface velocity attribute loading")
|
||||
if not dprops.particles.enable_fluid_particle_velocity_vector_attribute:
|
||||
dprops.particles.enable_fluid_particle_velocity_vector_attribute = True
|
||||
print("Enabled fluid particles velocity attribute loading")
|
||||
if not dprops.whitewater.enable_velocity_vector_attribute:
|
||||
dprops.whitewater.enable_velocity_vector_attribute = True
|
||||
print("Enabled whitewater velocity attribute loading")
|
||||
else:
|
||||
if dprops.surface.enable_velocity_vector_attribute:
|
||||
dprops.surface.enable_velocity_vector_attribute = False
|
||||
print("Disabled fluid surface velocity attribute from loading")
|
||||
if dprops.particles.enable_fluid_particle_velocity_vector_attribute:
|
||||
dprops.particles.enable_fluid_particle_velocity_vector_attribute = False
|
||||
print("Disabled fluid particles velocity attribute from loading")
|
||||
if dprops.whitewater.enable_velocity_vector_attribute:
|
||||
dprops.whitewater.enable_velocity_vector_attribute = False
|
||||
print("Disabled fluid whitewater velocity attribute from loading")
|
||||
|
||||
if dprops.surface.enable_speed_attribute:
|
||||
dprops.surface.enable_speed_attribute = False
|
||||
print("Disabled fluid surface Speed attribute from loading")
|
||||
if dprops.surface.enable_vorticity_vector_attribute:
|
||||
dprops.surface.enable_vorticity_vector_attribute = False
|
||||
print("Disabled fluid surface Vorticity attribute from loading")
|
||||
if dprops.surface.enable_viscosity_attribute:
|
||||
dprops.surface.enable_viscosity_attribute = False
|
||||
print("Disabled fluid surface Viscosity attribute from loading")
|
||||
if dprops.surface.enable_age_attribute:
|
||||
dprops.surface.enable_age_attribute = False
|
||||
print("Disabled fluid surface Age attribute from loading")
|
||||
if dprops.surface.enable_lifetime_attribute:
|
||||
dprops.surface.enable_lifetime_attribute = False
|
||||
print("Disabled fluid surface Lifetime attribute from loading")
|
||||
if dprops.surface.enable_whitewater_proximity_attribute:
|
||||
dprops.surface.enable_whitewater_proximity_attribute = False
|
||||
print("Disabled fluid surface Whitewater Proximity attribute from loading")
|
||||
|
||||
if hprops.alembic_export_color:
|
||||
bl_surface = dprops.mesh_cache.surface.get_cache_object()
|
||||
if bl_surface is not None:
|
||||
print("\nInitializing Alembic surface color export setup:")
|
||||
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")
|
||||
add_geometry_node_modifier(bl_surface, geometry_nodes_library, "FF_AlembicColorExportSurface")
|
||||
print("Finished initializing surface color export setup.")
|
||||
else:
|
||||
if dprops.surface.enable_color_attribute:
|
||||
dprops.surface.enable_color_attribute = False
|
||||
print("Disabled fluid surface Color attribute from loading")
|
||||
|
||||
# User may want source ID attribute for geoemtry nodes post processing
|
||||
"""
|
||||
if dprops.surface.enable_source_id_attribute:
|
||||
dprops.surface.enable_source_id_attribute = False
|
||||
print("Disabled fluid surface Source ID attribute from loading")
|
||||
"""
|
||||
|
||||
if dprops.particles.enable_fluid_particle_speed_attribute:
|
||||
dprops.particles.enable_fluid_particle_speed_attribute = False
|
||||
print("Disabled fluid particles Speed attribute from loading")
|
||||
if dprops.particles.enable_fluid_particle_vorticity_vector_attribute:
|
||||
dprops.particles.enable_fluid_particle_vorticity_vector_attribute = False
|
||||
print("Disabled fluid particles Vorticity attribute from loading")
|
||||
if dprops.particles.enable_fluid_particle_color_attribute:
|
||||
dprops.particles.enable_fluid_particle_color_attribute = False
|
||||
print("Disabled fluid particles Color attribute from loading")
|
||||
if dprops.particles.enable_fluid_particle_age_attribute:
|
||||
dprops.particles.enable_fluid_particle_age_attribute = False
|
||||
print("Disabled fluid particles Age attribute from loading")
|
||||
if dprops.particles.enable_fluid_particle_lifetime_attribute:
|
||||
dprops.particles.enable_fluid_particle_lifetime_attribute = False
|
||||
print("Disabled fluid particles Lifetime attribute from loading")
|
||||
if dprops.particles.enable_fluid_particle_whitewater_proximity_attribute:
|
||||
dprops.particles.enable_fluid_particle_whitewater_proximity_attribute = False
|
||||
print("Disabled fluid particles Whitewater Proximity attribute from loading")
|
||||
# User may want source ID attribute for geoemtry nodes post processing
|
||||
"""
|
||||
if dprops.particles.enable_fluid_particle_source_id_attribute:
|
||||
dprops.particles.enable_fluid_particle_source_id_attribute = False
|
||||
print("Disabled fluid particles Source ID attribute from loading")
|
||||
"""
|
||||
|
||||
if dprops.whitewater.enable_id_attribute:
|
||||
dprops.whitewater.enable_id_attribute = False
|
||||
print("Disabled whitewater ID attribute from loading")
|
||||
if dprops.whitewater.enable_lifetime_attribute:
|
||||
dprops.whitewater.enable_lifetime_attribute = False
|
||||
print("Disabled whitewater Lifetime attribute from loading")
|
||||
print("Finished optimizing attribute loading.")
|
||||
|
||||
|
||||
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 check_cache_velocity_data():
|
||||
hprops = bpy.context.scene.flip_fluid_helper
|
||||
dprops = bpy.context.scene.flip_fluid.get_domain_properties()
|
||||
if not hprops.alembic_export_velocity:
|
||||
return
|
||||
|
||||
print("\nSearching for velocity attribute cache data:")
|
||||
|
||||
cache_directory = dprops.cache.get_cache_abspath()
|
||||
bakefiles_directory = os.path.join(cache_directory, "bakefiles")
|
||||
|
||||
file_list = []
|
||||
if os.path.isdir(bakefiles_directory):
|
||||
file_list = os.listdir(bakefiles_directory)
|
||||
|
||||
surface_velocity_filecount = len([f for f in file_list if f.startswith("velocity")])
|
||||
fluid_particles_velocity_filecount = len([f for f in file_list if f.startswith("fluidparticlesvelocity")])
|
||||
foam_velocity_filecount = len([f for f in file_list if f.startswith("velocityfoam")])
|
||||
bubble_velocity_filecount = len([f for f in file_list if f.startswith("velocitybubble")])
|
||||
spray_velocity_filecount = len([f for f in file_list if f.startswith("velocityspray")])
|
||||
dust_velocity_filecount = len([f for f in file_list if f.startswith("velocitydust")])
|
||||
surface_velocity_filecount = (surface_velocity_filecount
|
||||
- foam_velocity_filecount
|
||||
- bubble_velocity_filecount
|
||||
- spray_velocity_filecount
|
||||
- dust_velocity_filecount)
|
||||
|
||||
display_warning = False
|
||||
if hprops.alembic_export_surface:
|
||||
bl_surface = dprops.mesh_cache.surface.get_cache_object()
|
||||
if bl_surface is not None:
|
||||
print("Searching for fluid surface velocity data...", end="")
|
||||
print(" FOUND " + str(surface_velocity_filecount) + " cache files.")
|
||||
if surface_velocity_filecount == 0:
|
||||
display_warning = True
|
||||
if hprops.alembic_export_fluid_particles:
|
||||
bl_fluid_particles = dprops.mesh_cache.particles.get_cache_object()
|
||||
if bl_fluid_particles is not None:
|
||||
print("Searching for fluid particles velocity data...", end="")
|
||||
print(" FOUND " + str(fluid_particles_velocity_filecount) + " cache files.")
|
||||
if fluid_particles_velocity_filecount == 0:
|
||||
display_warning = True
|
||||
if hprops.alembic_export_foam:
|
||||
bl_foam = dprops.mesh_cache.foam.get_cache_object()
|
||||
if bl_foam is not None:
|
||||
print("Searching for whitewater foam velocity data...", end="")
|
||||
print(" FOUND " + str(foam_velocity_filecount) + " cache files.")
|
||||
if foam_velocity_filecount == 0:
|
||||
display_warning = True
|
||||
if hprops.alembic_export_bubble:
|
||||
bl_bubble = dprops.mesh_cache.bubble.get_cache_object()
|
||||
if bl_bubble is not None:
|
||||
print("Searching for whitewater bubble velocity data...", end="")
|
||||
print(" FOUND " + str(bubble_velocity_filecount) + " cache files.")
|
||||
if bubble_velocity_filecount == 0:
|
||||
display_warning = True
|
||||
if hprops.alembic_export_spray:
|
||||
bl_spray = dprops.mesh_cache.spray.get_cache_object()
|
||||
if bl_spray is not None:
|
||||
print("Searching for whitewater spray velocity data...", end="")
|
||||
print(" FOUND " + str(spray_velocity_filecount) + " cache files.")
|
||||
if spray_velocity_filecount == 0:
|
||||
display_warning = True
|
||||
if hprops.alembic_export_dust:
|
||||
bl_dust = dprops.mesh_cache.dust.get_cache_object()
|
||||
if bl_dust is not None:
|
||||
print("Searching for whitewater dust velocity data...", end="")
|
||||
print(" FOUND " + str(dust_velocity_filecount) + " cache files.")
|
||||
if dust_velocity_filecount == 0:
|
||||
display_warning = True
|
||||
|
||||
if display_warning:
|
||||
warning_msg = "WARNING: One or more meshes contain no velocity data in the simulation"
|
||||
warning_msg += " cache files. Baking the surface, fluid particles, and/or whitewater velocity attribute"
|
||||
warning_msg += " is required for exporting velocity data to Alembic."
|
||||
print(warning_msg)
|
||||
|
||||
print("Finished searching for velocity attribute cache data.")
|
||||
|
||||
|
||||
def get_alembic_output_filepath():
|
||||
hprops = bpy.context.scene.flip_fluid_helper
|
||||
|
||||
script_arguments = None
|
||||
if "--" in sys.argv:
|
||||
script_arguments = sys.argv[sys.argv.index("--") + 1:]
|
||||
|
||||
# If an argument has been passed in, override the 'alembic_output_filepath' property
|
||||
if script_arguments is not None and len(script_arguments) >= 1:
|
||||
override_filepath = script_arguments[0]
|
||||
hprops.alembic_output_filepath = override_filepath
|
||||
print("Overriding Alembic output filepath to script argument at position 0: <" + override_filepath + ">")
|
||||
|
||||
alembic_filepath = hprops.get_alembic_output_abspath()
|
||||
if not alembic_filepath.endswith(".abc"):
|
||||
if alembic_filepath.endswith("."):
|
||||
alembic_filepath += "abc"
|
||||
else:
|
||||
alembic_filepath += ".abc"
|
||||
|
||||
return alembic_filepath
|
||||
|
||||
|
||||
dprops = bpy.context.scene.flip_fluid.get_domain_properties()
|
||||
if dprops is None:
|
||||
print("\nError: No domain found in Blend file. Hint: Did you remember to save the Blend file before running this operator? Exiting.")
|
||||
exit()
|
||||
|
||||
hprops = bpy.context.scene.flip_fluid_helper
|
||||
|
||||
print("\n*** Preparing Alembic Export ***\n")
|
||||
|
||||
if bpy.context.mode != 'OBJECT':
|
||||
# Meshes can only be exported in Object Mode
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
print("Viewport set to Object Mode.\n")
|
||||
|
||||
retval = check_cache_exists()
|
||||
if not retval:
|
||||
exit()
|
||||
|
||||
retval = initialize_simulation_mesh_selection()
|
||||
if not retval:
|
||||
exit()
|
||||
|
||||
initialize_velocity_export_and_attributes()
|
||||
check_cache_velocity_data()
|
||||
|
||||
print("\n*** Starting Alembic Export ***\n")
|
||||
|
||||
global_scale = hprops.alembic_global_scale
|
||||
frame_start, frame_end = get_export_frame_range()
|
||||
alembic_filepath = get_alembic_output_filepath()
|
||||
|
||||
print("Exporting Alembic to: <" + alembic_filepath + ">")
|
||||
print("Frame Range: " + str(frame_start) + " to " + str(frame_end))
|
||||
print("")
|
||||
|
||||
mesh_export_str = ""
|
||||
bl_surface = dprops.mesh_cache.surface.get_cache_object()
|
||||
if hprops.alembic_export_surface and bl_surface is not None:
|
||||
mesh_export_str += "Surface"
|
||||
bl_fluid_particles = dprops.mesh_cache.particles.get_cache_object()
|
||||
if hprops.alembic_export_fluid_particles and bl_fluid_particles is not None:
|
||||
mesh_export_str += "/FluidParticles"
|
||||
bl_foam = dprops.mesh_cache.foam.get_cache_object()
|
||||
if hprops.alembic_export_foam and bl_foam is not None:
|
||||
mesh_export_str += "/Foam"
|
||||
bl_bubble = dprops.mesh_cache.bubble.get_cache_object()
|
||||
if hprops.alembic_export_bubble and bl_bubble is not None:
|
||||
mesh_export_str += "/Bubble"
|
||||
bl_spray = dprops.mesh_cache.spray.get_cache_object()
|
||||
if hprops.alembic_export_spray and bl_spray is not None:
|
||||
mesh_export_str += "/Spray"
|
||||
bl_dust = dprops.mesh_cache.dust.get_cache_object()
|
||||
if hprops.alembic_export_dust and bl_dust is not None:
|
||||
mesh_export_str += "/Dust"
|
||||
|
||||
|
||||
EXPORT_FINISHED = False
|
||||
FRAME_END = frame_end
|
||||
TIMESTAMP = time.time()
|
||||
TOTAL_TIME = 0.0
|
||||
def frame_change_handler(scene):
|
||||
global EXPORT_FINISHED
|
||||
global FRAME_END
|
||||
global TIMESTAMP
|
||||
global TOTAL_TIME
|
||||
|
||||
if not EXPORT_FINISHED:
|
||||
current_time = time.time()
|
||||
elapsed_time = current_time - TIMESTAMP
|
||||
TIMESTAMP = current_time
|
||||
TOTAL_TIME += elapsed_time
|
||||
|
||||
info_msg = "Exported <" + mesh_export_str + ">"
|
||||
if hprops.alembic_export_velocity:
|
||||
info_msg += " with velocity data"
|
||||
if hprops.alembic_export_color:
|
||||
info_msg += " with color data"
|
||||
info_msg += " for frame " + str(scene.frame_current)
|
||||
info_msg += " in " + '{0:.3f}'.format(elapsed_time) + " seconds (total: " + '{0:.3f}'.format(TOTAL_TIME) + "s)"
|
||||
print(info_msg)
|
||||
|
||||
if scene.frame_current == FRAME_END:
|
||||
EXPORT_FINISHED = True
|
||||
|
||||
bpy.app.handlers.frame_change_post.append(frame_change_handler)
|
||||
|
||||
bpy.ops.wm.alembic_export(
|
||||
filepath=alembic_filepath,
|
||||
selected=True,
|
||||
start=frame_start,
|
||||
end=frame_end,
|
||||
vcolors=hprops.alembic_export_color,
|
||||
global_scale=global_scale)
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
set /a launch_attempts = MAX_LAUNCH_ATTEMPTS
|
||||
set /a launch_counter = %launch_attempts%
|
||||
:DoWhile
|
||||
if %launch_counter% == 0 goto EndDoWhile
|
||||
@echo on
|
||||
COMMAND_OPERATION
|
||||
@echo off
|
||||
if %errorlevel% == 0 goto EndDoWhile else (
|
||||
set /a current_restart = %launch_attempts% - %launch_counter% + 1
|
||||
set /a max_restarts = %launch_attempts% - 1
|
||||
echo --------------------------------------------------------------------------------
|
||||
echo SIMULATION TERMINATED: An unknown error has caused Blender to crash ^(error code %ERRORLEVEL%^)
|
||||
if %launch_counter% neq 1 (
|
||||
echo Attempting to re-launch simulation ^(attempt %current_restart% / %max_restarts%^)
|
||||
)
|
||||
echo --------------------------------------------------------------------------------
|
||||
)
|
||||
set /a launch_counter = %launch_counter% - 1
|
||||
if %launch_counter% gtr 0 goto DoWhile
|
||||
:EndDoWhile
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
import bpy, sys, os, threading, time, subprocess, queue
|
||||
|
||||
argv = sys.argv
|
||||
argv = argv[argv.index("--") + 1:]
|
||||
num_render_instances_option = int(argv[0])
|
||||
use_overwrite_option = int(argv[1])
|
||||
|
||||
_NUM_RENDER_INSTANCES = num_render_instances_option
|
||||
_USE_OVERWRITE = bool(use_overwrite_option)
|
||||
_RENDER_THREADS = []
|
||||
|
||||
|
||||
def _render_thread(settings, frameno):
|
||||
command = [settings["blender_binary_path"], "-b", settings["blend_filepath"], "-f", str(frameno)]
|
||||
subprocess.call(command, shell=False)
|
||||
|
||||
|
||||
def render_loop(settings):
|
||||
global _NUM_RENDER_INSTANCES
|
||||
global _RENDER_THREADS
|
||||
global _IS_SIMULATION_FINISHED
|
||||
|
||||
_RENDER_THREADS = [None] * _NUM_RENDER_INSTANCES
|
||||
|
||||
render_frame_queue = queue.Queue()
|
||||
for frameno in settings["frameno_list"]:
|
||||
render_frame_queue.put(frameno)
|
||||
|
||||
updates_per_second = 60
|
||||
while True:
|
||||
if not render_frame_queue.empty():
|
||||
available_thread_id = -1
|
||||
is_thread_available = False
|
||||
for i in range(len(_RENDER_THREADS)):
|
||||
if _RENDER_THREADS[i] is None or not _RENDER_THREADS[i].is_alive():
|
||||
available_thread_id = i
|
||||
is_thread_available = True
|
||||
break
|
||||
|
||||
if is_thread_available:
|
||||
frameno = render_frame_queue.get()
|
||||
_RENDER_THREADS[available_thread_id] = threading.Thread(target=_render_thread, args=(settings, frameno))
|
||||
_RENDER_THREADS[available_thread_id].start()
|
||||
|
||||
if render_frame_queue.empty():
|
||||
is_threads_running = False
|
||||
for thread in _RENDER_THREADS:
|
||||
if thread is not None and thread.is_alive():
|
||||
is_threads_running = True
|
||||
break
|
||||
if not is_threads_running:
|
||||
return
|
||||
|
||||
time.sleep(1.0/updates_per_second)
|
||||
|
||||
|
||||
def get_render_output_info():
|
||||
full_path = bpy.path.abspath(bpy.context.scene.render.filepath)
|
||||
directory_path = full_path
|
||||
|
||||
file_prefix = os.path.basename(directory_path)
|
||||
if file_prefix:
|
||||
directory_path = os.path.dirname(directory_path)
|
||||
|
||||
file_format_to_suffix = {
|
||||
"BMP" : ".bmp",
|
||||
"IRIS" : ".rgb",
|
||||
"PNG" : ".png",
|
||||
"JPEG" : ".jpg",
|
||||
"JPEG2000" : ".jp2",
|
||||
"TARGA" : ".tga",
|
||||
"TARGA_RAW" : ".tga",
|
||||
"CINEON" : ".cin",
|
||||
"DPX" : ".dpx",
|
||||
"OPEN_EXR_MULTILAYER" : ".exr",
|
||||
"OPEN_EXR" : ".exr",
|
||||
"HDR" : ".hdr",
|
||||
"TIFF" : ".tif",
|
||||
"WEBP" : ".webp",
|
||||
"AVI_JPEG" : ".avi",
|
||||
"AVI_RAW" : ".avi",
|
||||
"FFMPEG" : ".mp4"
|
||||
}
|
||||
|
||||
file_format = bpy.context.scene.render.image_settings.file_format
|
||||
file_suffix = file_format_to_suffix[file_format]
|
||||
|
||||
return directory_path, file_prefix, file_suffix
|
||||
|
||||
|
||||
hprops = bpy.context.scene.flip_fluid_helper
|
||||
directory_path, file_prefix, file_suffix = get_render_output_info()
|
||||
frame_start = bpy.context.scene.frame_start
|
||||
frame_end = bpy.context.scene.frame_end
|
||||
frame_step = bpy.context.scene.frame_step
|
||||
skipped_frame_filepaths = []
|
||||
rendered_frame_filepaths = []
|
||||
|
||||
frameno_list = list(range(frame_start, frame_end + 1, frame_step))
|
||||
if not _USE_OVERWRITE:
|
||||
filtered_frameno_list = []
|
||||
filename_list = os.listdir(directory_path)
|
||||
for frameno in frameno_list:
|
||||
frame_filename = file_prefix + str(frameno).zfill(4) + file_suffix
|
||||
frame_filepath = os.path.join(directory_path, frame_filename)
|
||||
if frame_filename not in filename_list:
|
||||
filtered_frameno_list.append(frameno)
|
||||
rendered_frame_filepaths.append(frame_filepath)
|
||||
else:
|
||||
skipped_frame_filepaths.append(frame_filepath)
|
||||
print("Frame exists, skipping frame <" + frame_filepath + ">")
|
||||
frameno_list = filtered_frameno_list
|
||||
else:
|
||||
for frameno in frameno_list:
|
||||
frame_filename = file_prefix + str(frameno).zfill(4) + file_suffix
|
||||
frame_filepath = os.path.join(directory_path, frame_filename)
|
||||
rendered_frame_filepaths.append(frame_filepath)
|
||||
|
||||
settings = {}
|
||||
settings["blender_binary_path"] = bpy.app.binary_path
|
||||
settings["blend_filepath"] = bpy.data.filepath
|
||||
settings["frame_start"] = bpy.context.scene.frame_start
|
||||
settings["frame_end"] = bpy.context.scene.frame_end
|
||||
settings["frame_step"] = bpy.context.scene.frame_step
|
||||
settings["use_overwrite"] = _USE_OVERWRITE
|
||||
settings["frameno_list"] = frameno_list
|
||||
|
||||
render_loop(settings)
|
||||
|
||||
print("\n***Multi Instance Render Complete***\n")
|
||||
|
||||
print("Blend Files: " + settings["blend_filepath"] + "\n")
|
||||
|
||||
print("Skipped Existing Frames: ")
|
||||
if skipped_frame_filepaths:
|
||||
for f in skipped_frame_filepaths:
|
||||
print("\t" + f)
|
||||
else:
|
||||
print("\tNo frames skipped")
|
||||
|
||||
print()
|
||||
|
||||
print("Rendered Frames: ")
|
||||
if rendered_frame_filepaths:
|
||||
for f in rendered_frame_filepaths:
|
||||
print("\t" + f)
|
||||
else:
|
||||
print("\tNo frames rendered")
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
import bpy, sys, os, pathlib, threading, time, subprocess, queue
|
||||
|
||||
argv = sys.argv
|
||||
argv = argv[argv.index("--") + 1:]
|
||||
num_render_instances_option = int(argv[0])
|
||||
use_overwrite_option = int(argv[1])
|
||||
|
||||
_NUM_RENDER_INSTANCES = num_render_instances_option
|
||||
_USE_OVERWRITE = bool(use_overwrite_option)
|
||||
_RENDER_THREADS = []
|
||||
|
||||
|
||||
def _render_thread(command_info):
|
||||
blend_filepath = command_info['blend_filepath']
|
||||
frameno = command_info['frameno']
|
||||
command = [bpy.app.binary_path, "-b", blend_filepath, "-f", str(frameno)]
|
||||
subprocess.call(command, shell=False)
|
||||
|
||||
|
||||
def render_loop(command_list):
|
||||
global _NUM_RENDER_INSTANCES
|
||||
global _RENDER_THREADS
|
||||
global _IS_SIMULATION_FINISHED
|
||||
|
||||
_RENDER_THREADS = [None] * _NUM_RENDER_INSTANCES
|
||||
|
||||
render_command_queue = queue.Queue()
|
||||
for command_text in command_list:
|
||||
render_command_queue.put(command_text)
|
||||
|
||||
updates_per_second = 60
|
||||
while True:
|
||||
if not render_command_queue.empty():
|
||||
available_thread_id = -1
|
||||
is_thread_available = False
|
||||
for i in range(len(_RENDER_THREADS)):
|
||||
if _RENDER_THREADS[i] is None or not _RENDER_THREADS[i].is_alive():
|
||||
available_thread_id = i
|
||||
is_thread_available = True
|
||||
break
|
||||
|
||||
if is_thread_available:
|
||||
command_info = render_command_queue.get()
|
||||
_RENDER_THREADS[available_thread_id] = threading.Thread(target=_render_thread, args=(command_info,))
|
||||
_RENDER_THREADS[available_thread_id].start()
|
||||
|
||||
if render_command_queue.empty():
|
||||
is_threads_running = False
|
||||
for thread in _RENDER_THREADS:
|
||||
if thread is not None and thread.is_alive():
|
||||
is_threads_running = True
|
||||
break
|
||||
if not is_threads_running:
|
||||
return
|
||||
|
||||
time.sleep(1.0/updates_per_second)
|
||||
|
||||
|
||||
def get_render_output_info():
|
||||
full_path = bpy.path.abspath(bpy.context.scene.render.filepath)
|
||||
directory_path = full_path
|
||||
|
||||
file_prefix = os.path.basename(directory_path)
|
||||
if file_prefix:
|
||||
directory_path = os.path.dirname(directory_path)
|
||||
|
||||
file_format_to_suffix = {
|
||||
"BMP" : ".bmp",
|
||||
"IRIS" : ".rgb",
|
||||
"PNG" : ".png",
|
||||
"JPEG" : ".jpg",
|
||||
"JPEG2000" : ".jp2",
|
||||
"TARGA" : ".tga",
|
||||
"TARGA_RAW" : ".tga",
|
||||
"CINEON" : ".cin",
|
||||
"DPX" : ".dpx",
|
||||
"OPEN_EXR_MULTILAYER" : ".exr",
|
||||
"OPEN_EXR" : ".exr",
|
||||
"HDR" : ".hdr",
|
||||
"TIFF" : ".tif",
|
||||
"WEBP" : ".webp",
|
||||
"AVI_JPEG" : ".avi",
|
||||
"AVI_RAW" : ".avi",
|
||||
"FFMPEG" : ".mp4"
|
||||
}
|
||||
|
||||
file_format = bpy.context.scene.render.image_settings.file_format
|
||||
file_suffix = file_format_to_suffix[file_format]
|
||||
|
||||
return directory_path, file_prefix, file_suffix
|
||||
|
||||
|
||||
def get_render_passes_info():
|
||||
# Pass-Suffix-Liste mit den zugehoerigen Listen
|
||||
hprops = bpy.context.scene.flip_fluid_helper
|
||||
pass_suffixes = [
|
||||
("BG_elements_only", hprops.render_passes_elements_only, hprops.render_passes_bg_elementslist),
|
||||
("REF_elements_only", hprops.render_passes_elements_only, hprops.render_passes_ref_elementslist),
|
||||
("objects_only", hprops.render_passes_objects_only, None),
|
||||
("fluidparticles_only", hprops.render_passes_fluidparticles_only, None),
|
||||
("fluid_only", hprops.render_passes_fluid_only, None),
|
||||
("fluid_shadows_only", hprops.render_passes_fluid_shadows_only, None),
|
||||
("reflr_only", hprops.render_passes_reflr_only, None),
|
||||
("bubblesanddust_only", hprops.render_passes_bubblesanddust_only, None),
|
||||
("foamandspray_only", hprops.render_passes_foamandspray_only, None),
|
||||
("FG_elements_only", hprops.render_passes_elements_only, hprops.render_passes_fg_elementslist),
|
||||
]
|
||||
|
||||
# Entferne leere Listen-Suffixe
|
||||
filtered_suffixes = [
|
||||
suffix for suffix, is_active, elements_list in pass_suffixes
|
||||
if is_active and (elements_list is None or len(elements_list) > 0)
|
||||
]
|
||||
|
||||
blend_file_directory = os.path.dirname(bpy.data.filepath)
|
||||
base_file_name = pathlib.Path(bpy.path.basename(bpy.data.filepath)).stem
|
||||
|
||||
info_dict_items = []
|
||||
for idx, suffix in enumerate(filtered_suffixes):
|
||||
pass_index = idx + 1
|
||||
|
||||
render_pass_blend_filename = f"{pass_index}_{base_file_name}_{suffix}.blend"
|
||||
blend_filepath = os.path.join(blend_file_directory, render_pass_blend_filename)
|
||||
|
||||
original_output_folder = bpy.path.abspath(bpy.context.scene.render.filepath)
|
||||
output_folder = os.path.dirname(original_output_folder)
|
||||
render_output_subfolder = f"{pass_index}_{suffix}"
|
||||
render_output_directory = os.path.join(output_folder, render_output_subfolder)
|
||||
output_filename = os.path.basename(original_output_folder)
|
||||
pass_file_prefix = f"{pass_index}_{output_filename}_{suffix}"
|
||||
|
||||
rendered_files = os.listdir(render_output_directory)
|
||||
|
||||
info = {}
|
||||
info['pass_index'] = pass_index
|
||||
info['blend_filepath'] = blend_filepath
|
||||
info['pass_file_prefix'] = pass_file_prefix
|
||||
info['rendered_files'] = rendered_files
|
||||
info_dict_items.append(info)
|
||||
|
||||
return info_dict_items
|
||||
|
||||
|
||||
hprops = bpy.context.scene.flip_fluid_helper
|
||||
render_passes_info = get_render_passes_info()
|
||||
_, _, image_file_extension = get_render_output_info()
|
||||
skip_rendered_frames = not _USE_OVERWRITE
|
||||
frame_start = bpy.context.scene.frame_start
|
||||
frame_end = bpy.context.scene.frame_end
|
||||
frame_step = bpy.context.scene.frame_step
|
||||
skipped_frame_filepaths = []
|
||||
rendered_frame_filepaths = []
|
||||
|
||||
render_command_queue = []
|
||||
for frameno in range(frame_start, frame_end + 1, frame_step):
|
||||
for pass_info in render_passes_info:
|
||||
blend_filepath = pass_info['blend_filepath']
|
||||
|
||||
if skip_rendered_frames:
|
||||
render_file_prefix = pass_info['pass_file_prefix']
|
||||
rendered_files = pass_info['rendered_files']
|
||||
rendered_filename = render_file_prefix + str(frameno).zfill(4) + image_file_extension
|
||||
if not rendered_filename in rendered_files:
|
||||
command_info = {}
|
||||
command_info['blend_filepath'] = blend_filepath
|
||||
command_info['frameno'] = frameno
|
||||
render_command_queue.append(command_info)
|
||||
else:
|
||||
command_info = {}
|
||||
command_info['blend_filepath'] = blend_filepath
|
||||
command_info['frameno'] = frameno
|
||||
render_command_queue.append(command_info)
|
||||
|
||||
render_loop(render_command_queue)
|
||||
|
||||
print("\n***Multi Instance Render Complete***\n")
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
import bpy, sys, os, platform, subprocess
|
||||
|
||||
argv = sys.argv
|
||||
argv = argv[argv.index("--") + 1:]
|
||||
frameno = int(argv[0])
|
||||
open_image_after = False
|
||||
if argv[1] == "1":
|
||||
open_image_after = True
|
||||
|
||||
# Video formats not support for single frame render
|
||||
# Set to a default image format
|
||||
video_formats = ["FFMPEG", "AVI_RAW", "AVI_JPEG"]
|
||||
if bpy.context.scene.render.image_settings.file_format in video_formats:
|
||||
default_image_format = "PNG"
|
||||
bpy.context.scene.render.image_settings.file_format = default_image_format
|
||||
|
||||
original_output_path = bpy.context.scene.render.filepath
|
||||
image_path = bpy.context.scene.render.frame_path(frame=frameno)
|
||||
|
||||
bpy.context.scene.frame_set(frameno)
|
||||
bpy.context.scene.render.filepath = image_path
|
||||
bpy.ops.render.render(write_still=True)
|
||||
bpy.context.scene.render.filepath = original_output_path
|
||||
|
||||
if open_image_after:
|
||||
print("Attempting to open image: <" + image_path + ">")
|
||||
system = platform.system()
|
||||
if system == "Windows":
|
||||
os.startfile(image_path)
|
||||
elif system == "Darwin":
|
||||
subprocess.call(["open", image_path])
|
||||
elif system == "Linux":
|
||||
subprocess.call(["xdg-open", image_path])
|
||||
pass
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import bpy, sys, os, platform, subprocess
|
||||
|
||||
argv = sys.argv
|
||||
argv = argv[argv.index("--") + 1:]
|
||||
frameno = int(argv[0])
|
||||
open_image_after = False
|
||||
if argv[1] == "1":
|
||||
open_image_after = True
|
||||
|
||||
original_output_path = bpy.context.scene.render.filepath
|
||||
image_path = bpy.context.scene.render.frame_path(frame=frameno)
|
||||
|
||||
bpy.context.scene.frame_set(frameno)
|
||||
bpy.context.scene.render.filepath = image_path
|
||||
bpy.ops.threedi.render_still(write_still=True)
|
||||
bpy.context.scene.render.filepath = original_output_path
|
||||
|
||||
if open_image_after:
|
||||
print("Attempting to open image: <" + image_path + ">")
|
||||
system = platform.system()
|
||||
if system == "Windows":
|
||||
os.startfile(image_path)
|
||||
elif system == "Darwin":
|
||||
subprocess.call(["open", image_path])
|
||||
elif system == "Linux":
|
||||
subprocess.call(["xdg-open", image_path])
|
||||
pass
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
import bpy, os, json, time
|
||||
|
||||
def play_sound(json_audio_filepath, block=False):
|
||||
if not (bpy.app.version >= (2, 80, 0)):
|
||||
# aud not supported in Blender 2.79 or lower
|
||||
return
|
||||
|
||||
try:
|
||||
if bpy.app.version >= (4, 2, 0):
|
||||
for module in bpy.context.preferences.addons:
|
||||
module_name = module.module
|
||||
if module_name.endswith("flip_fluids_addon"):
|
||||
prefs = bpy.context.preferences.addons[module_name].preferences
|
||||
break
|
||||
else:
|
||||
prefs = bpy.context.preferences.addons["flip_fluids_addon"].preferences
|
||||
except:
|
||||
return
|
||||
|
||||
if not prefs.enable_bake_alarm:
|
||||
return
|
||||
|
||||
import aud
|
||||
|
||||
with open(json_audio_filepath, 'r', encoding='utf-8') as f:
|
||||
json_data = json.loads(f.read())
|
||||
|
||||
audio_length = float(json_data["length"])
|
||||
audio_filename = json_data["filename"]
|
||||
audio_filepath = os.path.join(os.path.dirname(json_audio_filepath), audio_filename)
|
||||
|
||||
device = aud.Device()
|
||||
sound = aud.Sound(audio_filepath)
|
||||
handle = device.play(sound)
|
||||
|
||||
if block:
|
||||
time.sleep(audio_length)
|
||||
handle.stop()
|
||||
|
||||
|
||||
bpy.ops.flip_fluid_operators.bake_fluid_simulation_cmd()
|
||||
|
||||
resources_directory = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
||||
audio_json_filepath = os.path.join(resources_directory, "sounds", "alarm", "sound_data.json")
|
||||
play_sound(audio_json_filepath, block=True)
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
import bpy, os, json, time
|
||||
|
||||
def play_sound(json_audio_filepath, block=False):
|
||||
if not (bpy.app.version >= (2, 80, 0)):
|
||||
# aud not supported in Blender 2.79 or lower
|
||||
return
|
||||
|
||||
try:
|
||||
if bpy.app.version >= (4, 2, 0):
|
||||
for module in bpy.context.preferences.addons:
|
||||
module_name = module.module
|
||||
if module_name.endswith("flip_fluids_addon"):
|
||||
prefs = bpy.context.preferences.addons[module_name].preferences
|
||||
break
|
||||
else:
|
||||
prefs = bpy.context.preferences.addons["flip_fluids_addon"].preferences
|
||||
except:
|
||||
return
|
||||
|
||||
if not prefs.enable_bake_alarm:
|
||||
return
|
||||
|
||||
import aud
|
||||
|
||||
with open(json_audio_filepath, 'r', encoding='utf-8') as f:
|
||||
json_data = json.loads(f.read())
|
||||
|
||||
audio_length = float(json_data["length"])
|
||||
audio_filename = json_data["filename"]
|
||||
audio_filepath = os.path.join(os.path.dirname(json_audio_filepath), audio_filename)
|
||||
|
||||
device = aud.Device()
|
||||
sound = aud.Sound(audio_filepath)
|
||||
handle = device.play(sound)
|
||||
|
||||
if block:
|
||||
time.sleep(audio_length)
|
||||
handle.stop()
|
||||
|
||||
|
||||
|
||||
bpy.ops.flip_fluid_operators.bake_fluid_simulation_cmd()
|
||||
bpy.ops.wm.revert_mainfile()
|
||||
bpy.ops.flip_fluid_operators.helper_command_line_render()
|
||||
|
||||
resources_directory = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
||||
audio_json_filepath = os.path.join(resources_directory, "sounds", "alarm", "sound_data.json")
|
||||
play_sound(audio_json_filepath, block=True)
|
||||
+282
@@ -0,0 +1,282 @@
|
||||
import bpy, sys, os, threading, time, subprocess, pathlib
|
||||
from collections import namedtuple
|
||||
|
||||
argv = sys.argv
|
||||
argv = argv[argv.index("--") + 1:]
|
||||
num_render_instances_option = int(argv[0])
|
||||
use_overwrite_option = int(argv[1])
|
||||
|
||||
_NUM_RENDER_INSTANCES = num_render_instances_option
|
||||
_USE_OVERWRITE = bool(use_overwrite_option)
|
||||
_RENDER_THREADS = []
|
||||
_IS_SIMULATION_FINISHED = False
|
||||
|
||||
RenderCommandInfo = namedtuple('RenderCommandInfo', ['blendfile', 'frame'])
|
||||
|
||||
|
||||
def get_max_bakefile_frame(bakefiles_directory):
|
||||
bakefiles = os.listdir(bakefiles_directory)
|
||||
max_frameno = -1
|
||||
for f in bakefiles:
|
||||
base = f.split(".")[0]
|
||||
if not base.startswith("finished"):
|
||||
# a file named in the form finished######.txt is created
|
||||
# to signal that all cache files for the frame have been generated.
|
||||
continue
|
||||
|
||||
try:
|
||||
frameno = int(base[-6:])
|
||||
max_frameno = max(frameno, max_frameno)
|
||||
except:
|
||||
# In the case that there is a bakefile without a number
|
||||
pass
|
||||
return max_frameno
|
||||
|
||||
|
||||
def get_render_output_info():
|
||||
full_path = bpy.path.abspath(bpy.context.scene.render.filepath)
|
||||
directory_path = full_path
|
||||
|
||||
file_prefix = os.path.basename(directory_path)
|
||||
if file_prefix:
|
||||
directory_path = os.path.dirname(directory_path)
|
||||
|
||||
file_format_to_suffix = {
|
||||
"BMP" : ".bmp",
|
||||
"IRIS" : ".rgb",
|
||||
"PNG" : ".png",
|
||||
"JPEG" : ".jpg",
|
||||
"JPEG2000" : ".jp2",
|
||||
"TARGA" : ".tga",
|
||||
"TARGA_RAW" : ".tga",
|
||||
"CINEON" : ".cin",
|
||||
"DPX" : ".dpx",
|
||||
"OPEN_EXR_MULTILAYER" : ".exr",
|
||||
"OPEN_EXR" : ".exr",
|
||||
"HDR" : ".hdr",
|
||||
"TIFF" : ".tif",
|
||||
"WEBP" : ".webp",
|
||||
"AVI_JPEG" : ".avi",
|
||||
"AVI_RAW" : ".avi",
|
||||
"FFMPEG" : ".mp4"
|
||||
}
|
||||
|
||||
file_format = bpy.context.scene.render.image_settings.file_format
|
||||
file_suffix = file_format_to_suffix[file_format]
|
||||
|
||||
return directory_path, file_prefix, file_suffix
|
||||
|
||||
|
||||
def get_render_passes_info():
|
||||
# Pass-Suffix-Liste mit den zugehoerigen Listen
|
||||
hprops = bpy.context.scene.flip_fluid_helper
|
||||
pass_suffixes = [
|
||||
("BG_elements_only", hprops.render_passes_elements_only, hprops.render_passes_bg_elementslist),
|
||||
("REF_elements_only", hprops.render_passes_elements_only, hprops.render_passes_ref_elementslist),
|
||||
("objects_only", hprops.render_passes_objects_only, None),
|
||||
("fluidparticles_only", hprops.render_passes_fluidparticles_only, None),
|
||||
("fluid_only", hprops.render_passes_fluid_only, None),
|
||||
("fluid_shadows_only", hprops.render_passes_fluid_shadows_only, None),
|
||||
("reflr_only", hprops.render_passes_reflr_only, None),
|
||||
("bubblesanddust_only", hprops.render_passes_bubblesanddust_only, None),
|
||||
("foamandspray_only", hprops.render_passes_foamandspray_only, None),
|
||||
("FG_elements_only", hprops.render_passes_elements_only, hprops.render_passes_fg_elementslist),
|
||||
]
|
||||
|
||||
# Entferne leere Listen-Suffixe
|
||||
filtered_suffixes = [
|
||||
suffix for suffix, is_active, elements_list in pass_suffixes
|
||||
if is_active and (elements_list is None or len(elements_list) > 0)
|
||||
]
|
||||
|
||||
blend_file_directory = os.path.dirname(bpy.data.filepath)
|
||||
base_file_name = pathlib.Path(bpy.path.basename(bpy.data.filepath)).stem
|
||||
|
||||
info_dict_items = []
|
||||
for idx, suffix in enumerate(filtered_suffixes):
|
||||
pass_index = idx + 1
|
||||
|
||||
render_pass_blend_filename = f"{pass_index}_{base_file_name}_{suffix}.blend"
|
||||
blend_filepath = os.path.join(blend_file_directory, render_pass_blend_filename)
|
||||
|
||||
original_output_folder = bpy.path.abspath(bpy.context.scene.render.filepath)
|
||||
output_folder = os.path.dirname(original_output_folder)
|
||||
render_output_subfolder = f"{pass_index}_{suffix}"
|
||||
render_output_directory = os.path.join(output_folder, render_output_subfolder)
|
||||
output_filename = os.path.basename(original_output_folder)
|
||||
pass_file_prefix = f"{pass_index}_{output_filename}_{suffix}"
|
||||
|
||||
rendered_files = os.listdir(render_output_directory)
|
||||
|
||||
info = {}
|
||||
info['pass_index'] = pass_index
|
||||
info['blend_filepath'] = blend_filepath
|
||||
info['pass_file_prefix'] = pass_file_prefix
|
||||
info['rendered_files'] = rendered_files
|
||||
info_dict_items.append(info)
|
||||
|
||||
return info_dict_items
|
||||
|
||||
|
||||
def get_render_command_list_single_blend():
|
||||
frame_start = bpy.context.scene.frame_start
|
||||
frame_end = bpy.context.scene.frame_end
|
||||
frame_step = bpy.context.scene.frame_step
|
||||
skip_rendered_frames = not _USE_OVERWRITE
|
||||
|
||||
render_command_list = []
|
||||
for frameno in range(frame_start, frame_end + 1, frame_step):
|
||||
image_filepath = bpy.context.scene.render.frame_path(frame=frameno)
|
||||
if skip_rendered_frames and os.path.isfile(image_filepath):
|
||||
continue
|
||||
|
||||
command = RenderCommandInfo(blendfile=bpy.data.filepath, frame=frameno)
|
||||
render_command_list.append(command)
|
||||
|
||||
return render_command_list
|
||||
|
||||
|
||||
def get_render_command_list_render_passes():
|
||||
frame_start = bpy.context.scene.frame_start
|
||||
frame_end = bpy.context.scene.frame_end
|
||||
frame_step = bpy.context.scene.frame_step
|
||||
skip_rendered_frames = not _USE_OVERWRITE
|
||||
render_passes_info = get_render_passes_info()
|
||||
_, _, image_file_extension = get_render_output_info()
|
||||
|
||||
render_command_list = []
|
||||
for frameno in range(frame_start, frame_end + 1, frame_step):
|
||||
for pass_info in render_passes_info:
|
||||
blend_filepath = pass_info['blend_filepath']
|
||||
|
||||
if skip_rendered_frames:
|
||||
render_file_prefix = pass_info['pass_file_prefix']
|
||||
rendered_files = pass_info['rendered_files']
|
||||
rendered_filename = render_file_prefix + str(frameno).zfill(4) + image_file_extension
|
||||
if not rendered_filename in rendered_files:
|
||||
command = RenderCommandInfo(blendfile=blend_filepath, frame=frameno)
|
||||
render_command_list.append(command)
|
||||
else:
|
||||
command = RenderCommandInfo(blendfile=blend_filepath, frame=frameno)
|
||||
render_command_list.append(command)
|
||||
|
||||
return render_command_list
|
||||
|
||||
|
||||
def _render_thread(command):
|
||||
subprocess_command = [bpy.app.binary_path, "-b", command.blendfile, "-f", str(command.frame)]
|
||||
subprocess.call(subprocess_command, shell=False)
|
||||
|
||||
|
||||
def _render_sequence_thread(command, frame_start, frame_end):
|
||||
subprocess_command = [bpy.app.binary_path, "-b", command.blendfile, "-s", str(frame_start), "-e", str(frame_end), "-a"]
|
||||
subprocess.call(subprocess_command, shell=False)
|
||||
|
||||
|
||||
def render_loop(render_command_list):
|
||||
global _NUM_RENDER_INSTANCES
|
||||
global _RENDER_THREADS
|
||||
global _IS_SIMULATION_FINISHED
|
||||
|
||||
_RENDER_THREADS = [None] * _NUM_RENDER_INSTANCES
|
||||
|
||||
frame_start = bpy.context.scene.frame_start
|
||||
frame_end = bpy.context.scene.frame_end
|
||||
frame_step = bpy.context.scene.frame_step
|
||||
|
||||
hprops = bpy.context.scene.flip_fluid_helper
|
||||
render_single_blend_file = not hprops.render_passes
|
||||
render_single_threaded = _NUM_RENDER_INSTANCES == 1
|
||||
is_render_sequence_optimization_available = render_single_blend_file and render_single_threaded and frame_step == 1
|
||||
|
||||
dprops = bpy.context.scene.flip_fluid.get_domain_properties()
|
||||
cache_directory = dprops.cache.get_cache_abspath()
|
||||
bakefiles_directory = os.path.join(cache_directory, "bakefiles")
|
||||
|
||||
baked_frames = []
|
||||
render_command_queue = []
|
||||
|
||||
updates_per_second = 60
|
||||
while True:
|
||||
if not os.path.isdir(bakefiles_directory):
|
||||
continue
|
||||
|
||||
# Update render command queue
|
||||
max_frameno = get_max_bakefile_frame(bakefiles_directory)
|
||||
if max_frameno < 0:
|
||||
continue
|
||||
|
||||
if max_frameno not in baked_frames:
|
||||
if baked_frames:
|
||||
next_frame = baked_frames[-1] + 1
|
||||
else:
|
||||
next_frame = frame_start
|
||||
|
||||
for i in range(next_frame, max_frameno + 1):
|
||||
baked_frames.append(i)
|
||||
|
||||
new_commands = [command for command in render_command_list if command.frame <= max_frameno]
|
||||
render_command_queue += new_commands
|
||||
remaining_commands = [command for command in render_command_list if command.frame > max_frameno]
|
||||
render_command_list = remaining_commands
|
||||
|
||||
# Launch render worker thread
|
||||
if render_command_queue:
|
||||
available_thread_id = -1
|
||||
is_thread_available = False
|
||||
for i in range(len(_RENDER_THREADS)):
|
||||
if _RENDER_THREADS[i] is None or not _RENDER_THREADS[i].is_alive():
|
||||
available_thread_id = i
|
||||
is_thread_available = True
|
||||
break
|
||||
|
||||
if is_thread_available:
|
||||
if is_render_sequence_optimization_available:
|
||||
# Render a continuous frame sequence instead of shutting down Blender between frames
|
||||
sequence_start = render_command_queue[0].frame
|
||||
sequence_end = sequence_start
|
||||
for i in range(1, len(render_command_queue)):
|
||||
next_frame = render_command_queue[i].frame
|
||||
if next_frame == sequence_end + 1:
|
||||
sequence_end = next_frame
|
||||
else:
|
||||
break
|
||||
|
||||
next_command = render_command_queue.pop(0)
|
||||
render_command_queue = [command for command in render_command_queue if command.frame > sequence_end]
|
||||
|
||||
_RENDER_THREADS[available_thread_id] = threading.Thread(target=_render_sequence_thread, args=(next_command, sequence_start, sequence_end,))
|
||||
_RENDER_THREADS[available_thread_id].start()
|
||||
else:
|
||||
next_command = render_command_queue.pop(0)
|
||||
_RENDER_THREADS[available_thread_id] = threading.Thread(target=_render_thread, args=(next_command,))
|
||||
_RENDER_THREADS[available_thread_id].start()
|
||||
|
||||
# Check if render finished
|
||||
if _IS_SIMULATION_FINISHED:
|
||||
last_frameno = baked_frames[-1]
|
||||
if last_frameno == frame_end:
|
||||
is_threads_running = False
|
||||
for thread in _RENDER_THREADS:
|
||||
if thread is not None and thread.is_alive():
|
||||
is_threads_running = True
|
||||
break
|
||||
if not is_threads_running:
|
||||
return
|
||||
|
||||
time.sleep(1.0/updates_per_second)
|
||||
|
||||
|
||||
hprops = bpy.context.scene.flip_fluid_helper
|
||||
if hprops.render_passes:
|
||||
render_command_list = get_render_command_list_render_passes()
|
||||
else:
|
||||
render_command_list = get_render_command_list_single_blend()
|
||||
|
||||
render_loop_thread = threading.Thread(target=render_loop, args=(render_command_list,))
|
||||
render_loop_thread.start()
|
||||
|
||||
bpy.ops.flip_fluid_operators.bake_fluid_simulation_cmd()
|
||||
_IS_SIMULATION_FINISHED = True
|
||||
|
||||
render_loop_thread.join()
|
||||
+1
@@ -0,0 +1 @@
|
||||
Darwin 20.6.0 /Library/Developer/CommandLineTools/usr/bin/c++ AppleClang 12.0.5.12050022 2025-07-16 18:32:05 %z
|
||||
@@ -0,0 +1 @@
|
||||
Linux 4.4.0-210-generic /usr/bin/c++ GNU 9.4.0 1 2025-07-16 18:32:00 %z
|
||||
+1
@@ -0,0 +1 @@
|
||||
Windows 6.2.9200 C:/dev/mingw64/bin/c++.exe GNU 15.0.0 1 2025-07-16 18:32:00 -0700
|
||||
@@ -0,0 +1,28 @@
|
||||
Data for running example scenes in this directory and subdirectories are licensed
|
||||
under the MIT License:
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (C) 2025 Ryan L. Guy & Dennis Fassbaender
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
||||
1
|
||||
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
alarm.ogg is licensed under CC0 Public Domain
|
||||
https://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
Source: OpenGameArt.org
|
||||
https://opengameart.org/content/win-jingle
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"filename": "alarm.ogg",
|
||||
"length": 2.5
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
{
|
||||
"1.0.0": [
|
||||
"Added individual foam/bubble/spray whitewater counts to frame stats (issue #227)",
|
||||
"Added estimated bake time remaining under bake operator (issue #227)",
|
||||
"Added full material library",
|
||||
"Fixed assertion error during mesh generation (issue #232)",
|
||||
"Fixed addon 'AttributeError' (issue #248)",
|
||||
"Replaced baking progress percentage with frame number (issue #227)",
|
||||
"Desaturated debug grid colors (issue #227)",
|
||||
"Fixed missing/incorrect domain property names displayed in dopesheet (issue #266)",
|
||||
"Fixed bug where if library material was edited, it would not show up in the material list (issue #235)",
|
||||
"'Display console output' option in debug panel is now disabled by default",
|
||||
"All display settings are now set to 'Final' by default",
|
||||
"Whitewater 'Use Icosphere' option is now enabled by default",
|
||||
"Improved stability when exporting animated meshes",
|
||||
"Reworked how meshes are loaded and transformed (issue #209)",
|
||||
"Reduced false-positives when 'Remove particles with extreme velocities' option is enabled",
|
||||
"Removed functionality to set CPU/GPU ratio",
|
||||
"Merged 'GPU Particle Advection' and 'GPU Scalar Field' options into a single 'Enable GPU Features' option"
|
||||
],
|
||||
"1.0.1": [
|
||||
"Added FLIP Fluids presets",
|
||||
"Added FLIP Fluids material library",
|
||||
"Added functionality to invert fluid surface normals when in contact with obstacle objects (issue #281)",
|
||||
"Fixed error where addon stats could stop being processed (issue #280)",
|
||||
"Improved stability when removing particles with extreme velocities"
|
||||
],
|
||||
"1.0.2": [
|
||||
"Added support for OS X (experimental)",
|
||||
"Added support for Linux (experimental)",
|
||||
"Fixed bug where the addon would crash if all vertices of an Inflow or Outflow object are located outside of the domain"
|
||||
],
|
||||
"1.0.3": [
|
||||
"Added operator to preferences menu to check for version updates (issue #314)",
|
||||
"Added support for fluid surface motion blur rendering. Feature can be enabled in the 'FLIP Fluid Surface' Panel. (issue #87)",
|
||||
"Fixed bug where editing a preset would display an error (issue #301)",
|
||||
"Fixed bug that prevented viscous fluids from sticking to obstacles",
|
||||
"Fixed bug that caused 'Out of Memory' error when an Inflow or Outflow was located outside of the domain (issue #316)",
|
||||
"Fixed bug that would cause meshes to be misaligned if world scaling was enabled (issue #315)",
|
||||
"Fixed bug that caused mesh artifacts when 'GPU Features' was disabled (issue #317)"
|
||||
],
|
||||
"1.0.4": [
|
||||
"Added support for baking from the command line (issue #329)",
|
||||
"Added debug functionality to visualize the true domain bounds (issue #299)",
|
||||
"Added functionality to restrict viewport/render fluid display from the 'FLIP Fluid' physics button (issue #222)",
|
||||
"Added Inflow option to constrain fluid inside of the inflow object to match the inflow emission velocity. Allows inflow to work when submerged (issue #322). Allows low velocity values to have the effect of slowing down inflow emission (issue #90)",
|
||||
"Added volumetric water shader 'Water (volumetric)' created by Grant Wilk of Remington Graphics",
|
||||
"Added optimization to skip frame calculations if time step is zero-length (issue #350)",
|
||||
"Fixed bug that would require reloading a scene if an invalid cache directory was set before baking (issue #330)",
|
||||
"Addon will now display popup error message when exporting a preset package to an invalid directory (issue #320)",
|
||||
"Fixed bug where surface motion blur rendering would show a 'hard edge' of the object that was not properly blurred (issue #87)",
|
||||
"Fixed bug that would trigger an error if a deformable inflow was located outside of the domain",
|
||||
"Fixed UI issue to disable ability to insert keyframes into 'Hold Frame' option",
|
||||
"Removed 'Invert Surface-Contact Normals' option in 'FLIP Fluid Surface' settings. This option does not work as intended and is not useful.",
|
||||
"Fixed bug where whitewater particles would be killed when boundary behaviour was set to 'Ballistic' (issue #354)",
|
||||
"Fixed bug where changes to whitewater particle scale would not be reloaded in the viewport (issue #339)",
|
||||
"Fixed bug where renaming Inflow/Fluid target object in outliner would not rename object in Inflow/Fluid settings (issue #356)",
|
||||
"Improved forward/backward compatibility of .blend files between addon versions",
|
||||
"Improved performance of surface mesh generation",
|
||||
"Improved compatibility with various Linux distributions",
|
||||
"Removed GPU acceleration features. GPU methods have been entirely replaced with higher performance CPU methods.",
|
||||
"Removed 'Enable Experimental Optimization Features' option from Advanced Settings panel. These features are no longer experimental and are now fully integrated into the fluid engine."
|
||||
],
|
||||
"1.0.5": [
|
||||
"Added feature to control amount of whitewater generated by Obstacle objects (#385)",
|
||||
"Added a surface tension solver (#388)",
|
||||
"Added sheeting effects feature",
|
||||
"Added experimental support for Blender 2.80 (#404)",
|
||||
"Added meshing options to remove parts of surface mesh near the domain boundary",
|
||||
"Added meshing options to set offset for fluid-solid mesh interface",
|
||||
"Added meshing feature to set a custom object as a meshing volume. Only fluid inside of this object will be meshed.",
|
||||
"Added option to skip re-exporting animated meshes",
|
||||
"Added settings and option to set a custom baking frame range instead of using the timeline start/end values",
|
||||
"Added a savestates feature. Ability to rollback a simulation and resimulate from an earlier frame.",
|
||||
"Added a 'Beginner Friendly Mode' that limits UI to only show the most basic and commonly used parameters",
|
||||
"Added a Basic/Advanced settings mode for Whitewater panel (issue #384)",
|
||||
"Fixed bug where using world scaling would cause incorrect distribution of generated whitewater particles (issue #373)",
|
||||
"Fixed bug that would cause holes (missing triangles) in the surface mesh (issue #372)",
|
||||
"Fixed bug that would cause missing chunks near the boundary of the surface mesh (issue #372)",
|
||||
"Fixed bug that would cause banding artifacts in the surface mesh",
|
||||
"Fixed 'ResourceWarning' error when disabling and re-enabled addon",
|
||||
"Fixed bug that would cause bumpy mesh artifacts on edges of domain (issue #380)",
|
||||
"Fixed bug where bake would continue to run after closing Blender (issue #361)",
|
||||
"Fixed bug where Blender could crash while rendering in Cycles with the viewport open (issue #403)",
|
||||
"Fixed bug where copper preset could be loaded as coffee preset",
|
||||
"Fixed 'Value must be greater or equal to zero' error that could be triggered if domain bounding box is too thin (issue #397)",
|
||||
"Fixed bug where deleted objects could be exported to the simulator (issue #405)",
|
||||
"Fixed bug where particles could escape the domain and trigger an 'Out of Range' error (issue #415)",
|
||||
"Fixed precision error what could cause fluid meshes to be scaled incorrectly (issue #414)",
|
||||
"Fixed bug where the 'Reload Frame' operator could ignore reloading a frame (issue #419)",
|
||||
"Fixed bug where the intersection between inversed obstacles would be computed as solid instead of empty",
|
||||
"Fixed issue where Blender could crash during animated mesh export (#401)",
|
||||
"Fixed Linux/MacOS bug where a simulation could stop in the middle of baking. Huge thanks to Christian Schwarz for helping us solve this issue!",
|
||||
"Setting inflow 'Substep Emissions' to 0 will cause the inflow only emit fluid on the first substep of a frame",
|
||||
"Misc material and preset library fixes",
|
||||
"Improved collisions with thin obstacles",
|
||||
"Improved support and compatibility for loading .blend files created in older FLIP Fluids versions",
|
||||
"Performance improvements",
|
||||
"Stability improvements",
|
||||
"Meshing improvements"
|
||||
],
|
||||
"1.0.6": [
|
||||
"Added support for Blender 2.81",
|
||||
"Added operators to toolbox menu to automatically launch command line baking and rendering processes (Feature only supported on Windows)",
|
||||
"Added reminder in the addon installation/preferences menu and Physics panel to complete installation by restarting Blender",
|
||||
"Added warning about Blender 2.80 bugs to the addon installation/preferences menu and system console output",
|
||||
"Added a reminder to prevent render crashes by locking interface in Blender 2.8x to addon installation/preferences menu and system console output",
|
||||
"Added an operator to the FLIP Fluid Display Settings panel and toolshelf menu to automatically lock the interface (Blender 2.8x)",
|
||||
"Added an operator to the FLIP Fluid Display Settings panel and toolshelf menu to automatically set the render display mode to Fullscreen (Blender 2.79)",
|
||||
"Added monochromatic FLIP Fluids icon for Blender 2.8x",
|
||||
"Fixed issue that could cause frequent Blender 2.8x crashes during render, Alembic export, and rigid/cloth simulation baking (issue #403)",
|
||||
"Fixed bug where Inflow 'Substep Emissions' value could not be keyframed",
|
||||
"Fixed TypeError that could be triggered at the end of simulation baking (issue #469)",
|
||||
"Fixed bug where console output would still be displayed during mesh export when the 'Display Console Output' option was disabled",
|
||||
"Reduced amount of particle meshing artifacts on boundary of domain",
|
||||
"Addon no longer automatically deletes the FLIP Fluids cache when closing an unsaved .blend file",
|
||||
"Addon now automatically adds a smooth modifier (set to 0 iterations) to the fluid mesh objects",
|
||||
"Addon will now display an error if a user attempts to bake a simulation before completing installation"
|
||||
],
|
||||
"1.0.7": [
|
||||
"Version 1.0.7 is fully supported in Blender 2.79 and Blender 2.81. Blender 2.80 is not fully supported due to severe bugs that affect the FLIP Fluids addon.",
|
||||
"Updated addon to use new Blender 2.81 features that improve rendering and baking stability",
|
||||
"Added a new Dust particle type to the whitewater simulator. Dust particles are generated near obstacles that are marked as dust emitters. Dust particles are advected with the fluid velocity similar to bubble particles and sink towards the ground.",
|
||||
"Added a 'Dust Emission Strength' parameter to the Obstacle properties section that controls how much whitewater dust the object will generate",
|
||||
"Added 'Spray Emission Speed' parameter to the whitewater simulator that will scale the speed of emitted spray particles. Increase to generate larger and more exaggerated spray effects.",
|
||||
"Added option to FLIP Fluid Advanced panel to disable changing topology warning for animated meshes that change topology between frames. Warning: vertex velocities will not be computed for topology changing meshes.",
|
||||
"Added option to FLIP Fluid Simulation panel to automatically set domain preview resolution based on recommendation",
|
||||
"Surface and whitewater mesh objects can now be renamed and are no longer required to be child objects of the Domain",
|
||||
"Fixed misc compile errors and warnings for Linux/MacOS",
|
||||
"Fixed bug that could cause baking crashes when using the whitewater simulator",
|
||||
"Fixed bug that could prevent whitewater foam particles from transitioning into spray particles",
|
||||
"Fixed bug that could cause whitewater particle objects not to be loaded in the viewport",
|
||||
"Fixed bug that could cause incorrect particle geometry when switching between built-in and custom particle objects",
|
||||
"Fixed bug that could leave behind stray objects in the scene when removing whitewater meshes",
|
||||
"Fixed bug that could cause errors when re-loading addon scripts",
|
||||
"Fixed bug where the 'More Bake Settings' subsection of the FLIP Fluid Simulation panel could not be set as default values",
|
||||
"Fixed bug where rendering could be disrupted if the 'Auto Load Baked Frames' feature is enabled",
|
||||
"Fixed bug that could cause grid debugging tools not to display",
|
||||
"Fixed stray debugging print outs during simulation in the Blender System Console",
|
||||
"Addon will now initialize the fluid_surface mesh object with smooth shading by default",
|
||||
"Addon will not automatically toggle Cycles visibility on inflow/outflow/fluid objects according to the objects hide render property",
|
||||
"Addon will now automatically lock the Blender interface (Blender > Render > Lock Interface) upon creation of the domain to prevent render crashes in Blender 2.8x",
|
||||
"Addon can now visualize the domain bounds independently of the domain grid in the FLIP Fluid Debug panel",
|
||||
"Removed smoothing operations from FLIP Fluid Surface panel. Amount of smoothing should be set in the fluid_surface object smooth modifier",
|
||||
"Whitewater particle object can now be set as a built-in 6 sided cube in addition to a 20 sided icosphere or a custom object",
|
||||
"Whitewater display settings section in FLIP Fluid Display panel can now be collapsed in the UI",
|
||||
"Misc tooltip improvements",
|
||||
"Misc performance improvements"
|
||||
],
|
||||
"1.0.8": [
|
||||
"Version 1.0.8 is fully supported in Blender 2.79, 2.81, and 2.82. Blender 2.80 is not fully supported due to severe bugs that affect the FLIP Fluids addon.",
|
||||
"Updated world scaling system to include two scaling modes: Relative and Absolute",
|
||||
"Options to set Start/End timing values in FLIP Fluid simulation panel have been removed",
|
||||
"Added operators for copying command line baking/rendering commands to clipboard (Windows Only)",
|
||||
"Operator that automatically launches command line render no longer requires a FLIP Fluids Domain in the scene (Windows Only)",
|
||||
"Removed unsafe cache operators (move/copy/rename) from UI. Use your filebrowser for these operations, which is safer.",
|
||||
"Removed the Compute Chunks setting (automatic/manual) from the FLIP Fluids surface panel (no longer needed)",
|
||||
"Particle Scale will be displayed in red if the value is set to less than 1.0",
|
||||
"Gravity mode (Scene or Custom) in the FLIP Fluid World panel has been changed to a horizontal selector",
|
||||
"Removed optimization and performance settings from FLIP Fluid Advanced panel (no longer needed)",
|
||||
"Fixed: Issue where velocities could be ignored on deformable meshes",
|
||||
"Fixed: Issue where velocities of animated objects would be ignored if an inverse obstacle was present in the scene",
|
||||
"Fixed: Issue that would cause mesh geometry not to export correctly if the Hide from Viewports object option (monitor icon in outliner) is used",
|
||||
"Potential fix for 1st frame not rendering whitewater particles",
|
||||
"Fixed: Issue where edge split modifiers would not be ignored during mesh export",
|
||||
"Fixed: Incorrect default fluid_surface mesh type for OctaneRender",
|
||||
"Fixed: Issue where the fluid_surface object could become unrecoverable if deleted within the viewport",
|
||||
"Fixed: Issue where OpenGL point size for particle debugging could not be set in Blender 2.8",
|
||||
"Fixed: Issue where special filesystem characters could not be used in object name",
|
||||
"Fixed: Potential errors if simulation contained over 120 million particles",
|
||||
"Fixed: Issue where simulation data could become corrupted when running out of storage space",
|
||||
"Fixed: Incorrect frame loading when playback offset set to -1 or 1",
|
||||
"Fixed: Compositing uses the wrong cached frame during render",
|
||||
"Fixed: Potential crashes when rendering example scenes",
|
||||
"Fixed: Issue that could trigger an error during command line baking",
|
||||
"Fixed: Baking error message when switching a FLIP Fluids Domain to another simulation type",
|
||||
"Fixed: Issue that could cause a baking crash if an obstacle object was located entirely outside of the domain",
|
||||
"See our FLIP Fluids Weekly Development notes #10 for a detailed changelog (flipfluids.com/blog)"
|
||||
],
|
||||
"1.0.9": [
|
||||
"### FLIP Fluids version 1.0.9b adds many bug fixes, stability improvements, and by popular demand, a new solver feature using the APIC simulation method!",
|
||||
"Added an APIC solver using the Affine Particle-In-Cell method.",
|
||||
"Added an _Accuracy_ option to the viscosity solver to control the solver error tolerance.",
|
||||
"Added an operator to the FLIP Fluid Helper sidebar menu to generate a Windows batch file (.bat) to command line render each frame of an animation one by one.",
|
||||
"Added viewport visibility toggles to the fluid particle, force field, and obstacle debug tools.",
|
||||
"Added a UI warning and tooltip if the Estimated Surface Tension Substeps info value exceeds the allowed Max Frame Substeps Value.",
|
||||
"Bug Fix: Fixed issue in Blender 2.91+ where rendering fluid meshes with motion blur enabled could result in longer Cycles render times.",
|
||||
"Bug Fix: Fixed issue where low viscosity streams would have a velocity bias in the positive X/Y/Z direction.",
|
||||
"Bug Fix: Fixed an issue where many particles could become stuck to sharp obstacle edges which could lead to an unstable simulation.",
|
||||
"Bug Fix: Bug where using the inflow Constrain Inflow Velocity option could cause a bulge to form in the lower x/y/z corner of the domain.",
|
||||
"Bug Fix: Fixed issue where disabling the whitewater feature and resuming a simulation would result in invalid whitewater cache files being generated in the cache directory.",
|
||||
"Bug Fix: Issue where keyframing a min/max property could overwrite other min/max properties (issue #516).",
|
||||
"Bug Fix: Issue where the bake operator status could hang on Calculating time remaining....",
|
||||
"Bug Fix: UI issue where the Resume From Frame X label could be displayed in red text instead of the default white.",
|
||||
"Bug Fix: UI issue where domain FLIP operator displayed the hide/show viewport/render icons in reverse order compared to regular Blender convention.",
|
||||
"Bug Fix: UI issue where bake information would not be updated when using the Reset operator if the current cache directory did not exist.",
|
||||
"Bug Fix: An error that would prevent a helpful error message from being displayed when loading the fluid engine library.",
|
||||
"Bug Fix: Potential fix for render crashes when the Fluid Particle Debugging or Force Field Debugging tools are enabled.",
|
||||
"Bug Fix: Bug where using the FLIP Fluids Helper > Solid/Wireframe operator would deselect Fluid/Inflow/Outflow objects after execution.",
|
||||
"Bug Fix: Removed deprecated cache operators (Copy/Move/Rename) from being searchable and executable in the F3 operator search menu.",
|
||||
"Bug Fix: ValueError that could be triggered upon creating a domain if the .blend file was located on a different drive than the Blender installation.",
|
||||
"Bug Fix: 'TypeError' that could be triggered in Blender 2.93 by pressing the F3 operator search key.",
|
||||
"Bug Fix: Removed extraneous debugging code that would cause (harmless) error messages in Blender 2.79.",
|
||||
"Bug Fix: Fixed error messages in Blender 2.79 due to difference in icon names in Blender 2.8+.",
|
||||
"Example Scene Fix: Fixed volume_force_animated_character.blend example scene issue where the fluid objects would be emitted in the wrong direction. Corrected in the example scenes file as of March 25, 2021.",
|
||||
"Changed: The FLIP Fluids Helper > Solid/Wireframe operators no longer change the render visibility of the objects. This functionality has been split into a separate row of Show/Hide Render operators that sets the render visibility of all selected objects.",
|
||||
"Changed: Safety Factor (CFL Number) setting in the FLIP Fluid Advanced panel has moved from the Simulation Stability section to the Frame Substeps section. The Safety Factor option is more closely related to how the simulator calculates adaptive substeps.",
|
||||
"Blender Support: Updated addon code to be compatible with Python 3.9 for future versions of Blender.",
|
||||
"Blender Support: At the moment, there are no known compatibility issues between FLIP Fluids and Blender 2.93 Alpha. This may change as development of 2.93 progresses and bugs can be tracked in (issue #519).",
|
||||
"Improved accuracy of viscosity solver setup.",
|
||||
"Improved memory handling and storage of fluid particles and attributes.",
|
||||
"Improved stability and performance.",
|
||||
"### FLIP Fluids version 1.0.9a is a maintenance update to add small improvements and bug fixes reported since the last stable release of 1.0.9.",
|
||||
"MacOS Compatibility notes:",
|
||||
" Due to a [bug in Blender versions 2.80, 2.81, and 2.82](https://developer.blender.org/T68243), it will no longer be possible for us to support MacOS in these three versions. The FLIP Fluids addon on MacOS will still be supported in Blender 2.79, 2.83+, and 2.9+.",
|
||||
"Blender 2.92 Alpha support: as of January 5th 2021, the daily Blender builds now support the FLIP Fluids addon. In earlier 2.92 builds, a Python feature that the addon uses was missing.",
|
||||
"Added three new example scenes by popular request.",
|
||||
"Added a filesystem protection layer to enforce that all file removal operations are functioning correctly, reducing bugs related to human/development error.",
|
||||
"Added a workaround into the addon for a long-standing Blender bug (T71908) which causes keyframed render settings on the fluid meshes not to be evaluated during render.",
|
||||
"Bug Fix: Addon will no longer allow the FLIP Fluid current cache directory to be set as blank and will be set as a reasonable default value.",
|
||||
"Bug Fix: FLIP Fluids Helper menu command line tool operators displayed incorrectly on MacOS and Linux (issue #505).",
|
||||
"Bug Fix: FLIP Fluids Helper menu command line tool Copy to Clipboard operators were not functioning on MacOS and Linux (issue #505).",
|
||||
"Bug Fix: Fixed potential Out of Memory error that could be triggered if a force field object is located outside of the domain.",
|
||||
"Bug Fix: Fixed potential issue where the FLIP Fluid surface or whitewater object could lose it's material after reseting a bake.",
|
||||
"Bug Fix: Fixed issue where inflow particles could be seeded in an unnatural pattern (issue #509).",
|
||||
"Bug Fix: Incorrect frame used in the simulation for the inflow/fluid object speed value if this value was keyframe animated.",
|
||||
"Bug Fix: Potential crash if a curve guided force field had endcaps disabled while enabling a minimum distance for the force field.",
|
||||
"Bug Fix: Issue where exporting an animated curve guided force field could trigger a 'Changing Topology Warning'. Note: it is okay for all current force fields to change topology.",
|
||||
"Bug Fix: Issue where Remove Particles With Extreme Velocities could generate false-positives for a viscous fluid falling under regular gravity.",
|
||||
"Bug Fix: Issue where keyframed quaternion or axis-angle rotation was not supported (issue #515).",
|
||||
"Bug Fix: Issue where the baked debug tools (particle/obstacle/forcefield) would not be updated correctly if the simulation Time Scale value was set to 0.0.",
|
||||
"Bug Fix: Potential error messages caused by the addon detecting Blender 2.9x versions incorrectly.",
|
||||
"Bug Fix: Issue where a combination of high resolution and small world scaling could result in the surface preview mesh not generating.",
|
||||
"###FLIP Fluids version 1.0.9 is our biggest update yet! This version includes a large new force field feature set as well as many other features, tweaks, and workflow improvements. Thank you to all of the testers who helped us develop this new version!",
|
||||
"Compatibility notes older .blend files:",
|
||||
" FLIP Fluids 1.0.9 is fully compatible with .blend files and caches created in 1.0.8, however some settings have been replaced and updated. If opening an older .blend file, you may want to check the following settings and adjust if necessary:",
|
||||
" Check that the Surface/Whitewater display modes in the FLIP Fluid Display Settings panel are correct.",
|
||||
" If using a Fluid/Inflow object with velocity set to a target object, check that the Velocity Mode is correct.",
|
||||
"Changes to default behavior:",
|
||||
" Default value change: Update Settings on Resume in FLIP Fluid Simulation panel is now enabled by default.",
|
||||
" Default value change: Surface Subdivision in FLIP Fluid Surface panel is now set to 1 by default. Tip: set to 0 (low quality) for quicker iteration when prototying a simulation.",
|
||||
"Added 4 new force field modes:",
|
||||
" Point Force - A force field that attracts fluid towards a single point.",
|
||||
" Surface Force - A force field that attracts fluid towards the surface of a mesh.",
|
||||
" Volume Force - A force field that attracts fluid into the volume of a mesh.",
|
||||
" Can be used similarly to Blender's older Fluid Control feature that was removed since Blender 2.82.",
|
||||
" Curve Guide Force - A force field that attracts towards or along a curve, or to spin around a curve.",
|
||||
" More force field modes are in development! Try our experimental versions here.",
|
||||
"Added 7 new example scenes to showcase the FLIP Fluids force field feature set, including detailed notes about the simulation setup and settings (Blender 2.82+, 2.9+ only).",
|
||||
"Added force field debug visualizer to FLIP Fluid Debug panel.",
|
||||
"Added Force Field Resolution option to FLIP Fluid World panel.",
|
||||
"Added a README.html file to the Blender Market product downloads that contains info and links for how to get started with the addon.",
|
||||
"Added a Grid Info section to the FLIP Fluids Simulation panel to display info about the simulation grid including tooltips to help explain the simulation grid.",
|
||||
"Added feature to upscale a simulation to an increased resolution on resuming the bake.",
|
||||
"Added functionality for Inflow/Fluid objects to emit fluid in the direction of the object's local axis.",
|
||||
"Added functionality to Skip Re-Export of static and keyframed meshes in addition to skipping animated meshes.",
|
||||
"Added Force Re-Export On Next Bake feature for FLIP Fluid simulation objects.",
|
||||
"Added expanded functionality for skipping/forcing mesh data to be exported in Settings and Mesh Export.",
|
||||
"Added functionality to link exported geometry data from another cache directory in FLIP Fluid Cache panel.",
|
||||
"Added exponent precision editing for viscosit and surface tension values.",
|
||||
"Added preferences option to rename the FLIP Fluids toolshelf panel name.",
|
||||
"Added preferences option to display links to relevant documentation in the UI.",
|
||||
"Added UI reminder to display if the preferences Beginner Friendly Mode is activated.",
|
||||
"Added functionality for Enable Stable Rendering operator to also undo this operation (Blender 2.8+ only).",
|
||||
"Added prompt/warning to Domain UI to warn that the .blend file has not been saved. Includes operator to open the save file menu.",
|
||||
"Added feature and organized FLIP Fluids Helper Menu panels:",
|
||||
" Added domain bake and cache operators to the FLIP Fluids Helper menu.",
|
||||
" Added Create Domain operator to FLIP Fluids Helper Menu to generate a domain depending on the context of what type of objects are selected and in your scene.",
|
||||
" Added operators to FLIP Fluids Helper Menu to select all simulation objects of a certain type (Obstacle/Fluid/Inflow/Outflow/ForceField).",
|
||||
" Added operators to FLIP Fluids Helper Menu to help organize your simulation objects in the Blender Outliner.",
|
||||
" Added Override Frame settings to FLIP Fluids Helper Menu that works similar to the setting of the same name in Blender's Alembic Cache modifier.",
|
||||
"Updated for compatibility with latest version of OctaneRender.",
|
||||
"Updated addon packaging, distribution, and testing process to be automated to reduce issues related to human-error.",
|
||||
"Updated Blender Market product downloads naming conventions to use more consistent naming format that includes the date that the file was last updated.",
|
||||
"Removed Rigid/Deformable mesh option for Inflow object. The simulator will now automatically detect whether the object is rigid or deformable.",
|
||||
"Removed Preserve Foam options from FLIP Fluid Whitewater UI. These settings were not working as expected and are no longer needed.",
|
||||
"Fixed: potential compatibility issues on MacOS systems.",
|
||||
"Fixed: bug where command line tools would not be displayed for MacOS/Linux operating systems.",
|
||||
"Fixed: issue where rectangle artifacts could appear in the fluid surface preview mesh (issue #491).",
|
||||
"Fixed: bug in Blender versions 2.9+ where toggling a FLIP object's render visibility would not update the object visibility in the viewport rendered display.",
|
||||
"Fixed: error during export that could be triggered by exporting an Empty type object as a fluid/inflow target.",
|
||||
"Fixed: issue where Empty type objects could be exported to incorrect locations within the simulator.",
|
||||
"Fixed: issue where the simulation mesh could be loaded into the viewport during animated object export, causing a very slow export process.",
|
||||
"Fixed: bug that could cause a crash if viscosity feature was enabled while simulating small amounts of fluid.",
|
||||
"Fixed: bug that could cause a crash if a object contained all vertices outside of the domain.",
|
||||
"Fixed: issue where changing particle size in the FLIP Fluid Debug particle debugging tool would not affect the draw size.",
|
||||
"Fixed: issue that was causing inflow object to require too much memory.",
|
||||
"Fixed: issue where Strawberry Splash example scene was not compatible with newer versions of Blender.",
|
||||
"Fixed: bug where a rare divide-by-zero error could cause the simulation to collapse in on itself.",
|
||||
"Fixed: issue where a mesh containing a zero-area triangle could cause a crash.",
|
||||
"Fixed: issue where an Attribute Error could be displayed when selecting the Domain object.",
|
||||
"Fixed: possible FLIP Fluid Stats alignment issue when selecting a frame that was outside of the cache range.",
|
||||
"Fixed: issue where FLIP Fluid Stats panel could display out-of-date info after a cache reset.",
|
||||
"Fixed: issue where FLIP Fluid toolshelf menu was missing operator to select the whitewater dust object.",
|
||||
"Fixed: Fixed potential crash issues that could be triggered when using Blender's Undo (Ctrl+Z) after creating a domain.",
|
||||
"Fixed: bug where FLIP Fluid Simulation panel would not be drawn in the case that the user has run out of drive space during the previous simulation.",
|
||||
"General performance improvement of 10% - 15% for medium to large simulations.",
|
||||
"Improved speed and flexibility of geometry export system.",
|
||||
"Improved accuracy of surface tension calculations to improve stability (prevent blow-ups).",
|
||||
"Improved multithreaded performance of adding new fluid particles into simulation domain.",
|
||||
"Improved performance in grid initialization.",
|
||||
"Improved performance in handling FLIP Fluid Obstacle objects.",
|
||||
"Miscellaneous UI tweaks, usability, stability, reliability improvements."
|
||||
],
|
||||
"1.1.0": [
|
||||
"### FLIP Fluids 1.1.0 is a maintenance update that adds bug fixes and small improvements!",
|
||||
"Blender 3.0 Compatibility: Blender 3.0 is still in development and is set to release in October 2021. At the moment, there are no known issues when using Blender 3.0 or the Blender 3.0 Cycles-X branch with this version of the FLIP Fluids addon.",
|
||||
" Compatibility may break as Blender 3.0 is developed. Issues related to Blender 3.0 compatibility can be reported and tracked on the GitHub project page.",
|
||||
"Added support for the Apple Silicon chip.",
|
||||
"Added functionality to the Automatic Command Line Bake operator (Windows Only):",
|
||||
" If a simulation error occurs that stops the simulation, the operator will now attempt to automatically re-launch and resume the simulation. Certain errors such as 'Out of Memory' errors can be solved by re-launching a simulation.",
|
||||
" If Blender crashes, the command line bake will try to detect the crash and attempt to re-launch Blender and the baking process.",
|
||||
" The max number of re-launch attempts can be set in the FLIP Fluid Preferences menu.",
|
||||
"Added 'Remove Mesh Near Domain' feature support for the preview mesh.",
|
||||
"Added operator to FLIP Fluid Cache panel to set the cache location to a directory based on the name of the .blend file.",
|
||||
"Added +/- operators to the FLIP Fluid Cache panel to increment/decrement a number at the end of a cache directory, similar to the icons when saving a .blend file.",
|
||||
"Added support for all render output image file types when using the Helper > Generate Batch File operator.",
|
||||
"Added support for curves that use the Poly spline type when used as a Curve Guided Force Field.",
|
||||
"Improved support for fracture simulations set as a FLIP Fluid Obstacle where the fracture simulation contains non-manifold geometry.",
|
||||
" Instead of ignoring the entire mesh when non-manifold geometry is detected, the simulator will only ignore fractured pieces of the mesh that contain non-manifold geometry.",
|
||||
"Bug Fix: Simulation will no longer stop if a frame statistics temporary file is found to be in use and unable to be deleted (issue #529).",
|
||||
"Bug Fix: Issue where command line operators may not work if spaces are contained in the Blender executable path, specifically when located in C:/Program Files/.",
|
||||
"Bug Fix: Fixed inconsistent UI issues (issue #533).",
|
||||
"Bug Fix: Issue where non-mesh type objects could be selected as a custom whitewater particle object, leading to an error during render.",
|
||||
"Bug Fix: Re-fixed preview rectangle artifacts issue that was introduced as a side effect by another bug fix (issue #491).",
|
||||
"Bug Fix: Issue where the whitewater display percentage setting loaded an incorrect amount of whitewater after resuming a simulation.",
|
||||
"Bug Fix: Fixed a FileNotFoundError when using the FLIP Fluids Helper > Generate Batch File if the render output location was set to a relative path.",
|
||||
"Bug Fix: fixed issue where Helper > Generate Batch File operator did not support image file prefixes in the render output location.",
|
||||
"Bug Fix: When baking from the command line and an error is encountered within the simulation, an error message will now be output correctly to the command line window.",
|
||||
"Bug Fix: The cache directory can no longer be set to a location directly relative to the .blend file (ex: '//').",
|
||||
"Bug Fix: Fixed issue where liquid could be spawned with triangle line artifacts for cuboid shaped Fluid objects in high resolution simulations.",
|
||||
"Bug Fix: Crash that could be caused by using undo after activating the Create Domain operator on a selected object.",
|
||||
"Bug Fix: Fixed incorrect render issue when 'Render > Persistent Data' option is enabled. Note: with this option enabled, rendering can be less stable. It is recommended to render through the command line if enabling this option.",
|
||||
"Bug Fix: Fixed issue where a curve or empty type object could not be added as a force field object through the helper menu.",
|
||||
"Bug Fix: (Blender 3.0) TypeError which prevents fluid surface object from being generated upon creation of a domain.",
|
||||
"Bug Fix: (Blender 3.0) KeyError generated upon starting a simulation.",
|
||||
"Bug Fix: (Blender 3.0) Immediate crash upon starting a render of a FLIP Fluids addon cache generated in Blender 2.93 or lower."
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user