From 6977ed7c2b7abc938935b4515185637ec14a59fe Mon Sep 17 00:00:00 2001 From: Ryan G Date: Mon, 12 Apr 2021 10:13:24 -0700 Subject: [PATCH] new demo version 0.0.9b! --- LICENSE_MIT.md | 2 +- README.md | 4 +- __init__.py | 2 +- build.py | 2 +- cmake/CMakeLists.txt | 4 +- src/addon/__init__.py.in | 11 +- src/addon/bake.py | 144 +++- src/addon/exit_handler.py | 2 +- src/addon/export.py | 12 +- src/addon/filesystem/__init__.py | 2 +- .../filesystem/filesystem_protection_layer.py | 9 +- src/addon/materials/__init__.py | 2 +- src/addon/materials/material_library.py | 2 +- src/addon/objects/__init__.py | 2 +- src/addon/objects/flip_fluid_aabb.py | 2 +- src/addon/objects/flip_fluid_cache.py | 14 +- .../objects/flip_fluid_geometry_database.py | 2 +- .../flip_fluid_geometry_export_object.py | 2 +- .../objects/flip_fluid_geometry_exporter.py | 2 +- src/addon/objects/flip_fluid_map.py | 2 +- .../objects/flip_fluid_material_library.py | 8 +- src/addon/objects/flip_fluid_preset_stack.py | 2 +- src/addon/operators/__init__.py | 2 +- src/addon/operators/bake_operators.py | 39 +- src/addon/operators/cache_operators.py | 14 +- .../operators/draw_force_field_operators.py | 22 +- src/addon/operators/draw_grid_operators.py | 18 +- .../operators/draw_particles_operators.py | 22 +- src/addon/operators/error_operators.py | 2 +- src/addon/operators/export_operators.py | 6 +- src/addon/operators/helper_operators.py | 187 ++++- src/addon/operators/material_operators.py | 2 +- src/addon/operators/object_operators.py | 2 +- src/addon/operators/preferences_operators.py | 4 +- src/addon/operators/preset_operators.py | 2 +- src/addon/operators/render_operators.py | 2 +- src/addon/operators/world_operators.py | 2 +- src/addon/presets/__init__.py | 2 +- src/addon/presets/preset_library.py | 20 +- src/addon/properties/__init__.py | 2 +- src/addon/properties/custom_properties.py | 2 +- .../properties/domain_advanced_properties.py | 28 +- .../properties/domain_bake_properties.py | 11 +- .../properties/domain_cache_properties.py | 2 +- .../properties/domain_debug_properties.py | 83 +- .../properties/domain_materials_properties.py | 2 +- .../properties/domain_presets_properties.py | 2 +- src/addon/properties/domain_properties.py | 2 +- .../properties/domain_render_properties.py | 2 +- .../domain_simulation_properties.py | 24 +- .../properties/domain_stats_properties.py | 50 +- .../properties/domain_surface_properties.py | 2 +- .../domain_whitewater_properties.py | 2 +- .../properties/domain_world_properties.py | 55 +- src/addon/properties/flip_fluid_properties.py | 2 +- src/addon/properties/fluid_properties.py | 2 +- .../properties/force_field_properties.py | 2 +- src/addon/properties/helper_properties.py | 2 +- src/addon/properties/inflow_properties.py | 2 +- src/addon/properties/material_properties.py | 2 +- src/addon/properties/object_properties.py | 6 +- src/addon/properties/obstacle_properties.py | 2 +- src/addon/properties/outflow_properties.py | 2 +- .../properties/preferences_properties.py | 10 +- src/addon/properties/preset_properties.py | 2 +- src/addon/render.py | 4 +- .../resources/version_data/versions.json | 55 +- src/addon/types.py | 9 +- src/addon/ui/__init__.py | 30 +- src/addon/ui/cache_object_ui.py | 2 +- src/addon/ui/domain_advanced_ui.py | 71 +- src/addon/ui/domain_cache_ui.py | 2 +- src/addon/ui/domain_debug_ui.py | 37 +- src/addon/ui/domain_display_ui.py | 7 +- src/addon/ui/domain_materials_ui.py | 2 +- src/addon/ui/domain_presets_ui.py | 2 +- src/addon/ui/domain_simulation_ui.py | 35 +- src/addon/ui/domain_stats_ui.py | 2 +- src/addon/ui/domain_surface_ui.py | 2 +- src/addon/ui/domain_ui.py | 2 +- src/addon/ui/domain_whitewater_ui.py | 7 +- src/addon/ui/domain_world_ui.py | 15 +- src/addon/ui/fluid_ui.py | 2 +- src/addon/ui/force_field_ui.py | 6 +- src/addon/ui/helper_ui.py | 47 +- src/addon/ui/inflow_ui.py | 2 +- src/addon/ui/none_ui.py | 2 +- src/addon/ui/obstacle_ui.py | 2 +- src/addon/ui/outflow_ui.py | 2 +- src/addon/utils/__init__.py | 2 +- src/addon/utils/api_workaround_utils.py | 18 +- src/addon/utils/cache_utils.py | 2 +- src/addon/utils/export_utils.py | 24 +- src/addon/utils/installation_utils.py | 2 +- src/addon/utils/preset_utils.py | 2 +- src/addon/utils/ui_utils.py | 2 +- .../utils/version_compatibility_utils.py | 16 +- src/engine/aabb.cpp | 2 +- src/engine/aabb.h | 2 +- src/engine/array3d.h | 2 +- src/engine/arrayview3d.h | 2 +- src/engine/blockarray3d.h | 2 +- src/engine/boundedbuffer.h | 2 +- src/engine/c_bindings/aabb_c.h | 2 +- src/engine/c_bindings/cbindings.cpp | 2 +- src/engine/c_bindings/cbindings.h | 2 +- src/engine/c_bindings/diffuseparticle_c.h | 2 +- src/engine/c_bindings/fluidsimulation_c.cpp | 114 ++- src/engine/c_bindings/forcefield_c.cpp | 2 +- src/engine/c_bindings/forcefieldcurve_c.cpp | 2 +- src/engine/c_bindings/forcefieldgrid_c.cpp | 2 +- src/engine/c_bindings/forcefieldpoint_c.cpp | 2 +- src/engine/c_bindings/forcefieldsurface_c.cpp | 2 +- src/engine/c_bindings/forcefieldvolume_c.cpp | 2 +- src/engine/c_bindings/gridindex_c.h | 2 +- src/engine/c_bindings/markerparticle_c.h | 2 +- src/engine/c_bindings/meshfluidsource_c.cpp | 2 +- src/engine/c_bindings/meshobject_c.cpp | 2 +- src/engine/c_bindings/openclutils_c.cpp | 2 +- src/engine/c_bindings/vector3_c.h | 2 +- src/engine/clscalarfield.cpp | 2 +- src/engine/clscalarfield.h | 2 +- src/engine/collision.cpp | 2 +- src/engine/collision.h | 2 +- src/engine/diffuseparticle.h | 2 +- src/engine/diffuseparticlesimulation.cpp | 478 ++++++----- src/engine/diffuseparticlesimulation.h | 39 +- src/engine/fluidmaterialgrid.cpp | 2 +- src/engine/fluidmaterialgrid.h | 2 +- src/engine/fluidsimassert.h | 2 +- src/engine/fluidsimulation.cpp | 751 ++++++++++++++---- src/engine/fluidsimulation.h | 95 ++- src/engine/forcefield.cpp | 2 +- src/engine/forcefield.h | 2 +- src/engine/forcefieldcurve.cpp | 2 +- src/engine/forcefieldcurve.h | 2 +- src/engine/forcefieldgravityscalegrid.h | 2 +- src/engine/forcefieldgrid.cpp | 2 +- src/engine/forcefieldgrid.h | 2 +- src/engine/forcefieldpoint.cpp | 2 +- src/engine/forcefieldpoint.h | 2 +- src/engine/forcefieldsurface.cpp | 2 +- src/engine/forcefieldsurface.h | 2 +- src/engine/forcefieldutils.cpp | 2 +- src/engine/forcefieldutils.h | 2 +- src/engine/forcefieldvolume.cpp | 2 +- src/engine/forcefieldvolume.h | 2 +- src/engine/fragmentedvector.h | 2 +- src/engine/grid3d.h | 2 +- src/engine/gridindexkeymap.cpp | 2 +- src/engine/gridindexkeymap.h | 2 +- src/engine/gridindexvector.cpp | 2 +- src/engine/gridindexvector.h | 2 +- src/engine/gridutils.cpp | 2 +- src/engine/gridutils.h | 2 +- src/engine/influencegrid.cpp | 2 +- src/engine/influencegrid.h | 2 +- src/engine/interpolation.cpp | 2 +- src/engine/interpolation.h | 2 +- src/engine/kernels/kernels.cpp.in | 2 +- src/engine/kernels/kernels.h | 2 +- src/engine/kernels/scalarfield.cl | 2 +- src/engine/kernels/trilinearinterpolate.cl | 2 +- src/engine/levelsetsolver.cpp | 2 +- src/engine/levelsetsolver.h | 2 +- src/engine/levelsetutils.cpp | 2 +- src/engine/levelsetutils.h | 2 +- src/engine/logfile.cpp | 2 +- src/engine/logfile.h | 2 +- src/engine/macvelocityfield.cpp | 2 +- src/engine/macvelocityfield.h | 2 +- src/engine/main.cpp | 3 +- src/engine/markerparticle.h | 13 +- src/engine/meshfluidsource.cpp | 2 +- src/engine/meshfluidsource.h | 2 +- src/engine/meshlevelset.cpp | 2 +- src/engine/meshlevelset.h | 2 +- src/engine/meshobject.cpp | 2 +- src/engine/meshobject.h | 2 +- src/engine/meshutils.cpp | 2 +- src/engine/meshutils.h | 2 +- src/engine/noisegenerationutils.cpp | 2 +- src/engine/noisegenerationutils.h | 2 +- src/engine/opencl_bindings/clcpp.cpp | 2 +- src/engine/opencl_bindings/clcpp.h | 2 +- src/engine/openclutils.cpp | 2 +- src/engine/openclutils.h | 2 +- src/engine/particleadvector.cpp | 2 +- src/engine/particleadvector.h | 2 +- src/engine/particlelevelset.cpp | 12 +- src/engine/particlelevelset.h | 5 +- src/engine/particlemaskgrid.cpp | 2 +- src/engine/particlemaskgrid.h | 2 +- src/engine/particlemesher.cpp | 2 +- src/engine/particlemesher.h | 2 +- src/engine/particlesheeter.cpp | 26 +- src/engine/particlesheeter.h | 7 +- src/engine/particlesystem.cpp | 523 ++++++++++++ src/engine/particlesystem.h | 314 ++++++++ src/engine/pcgsolver/pcgsolver.h | 3 +- src/engine/polygonizer3d.cpp | 2 +- src/engine/polygonizer3d.h | 2 +- src/engine/pressuresolver.cpp | 2 +- src/engine/pressuresolver.h | 2 +- src/engine/pyfluid/__init__.py | 2 +- src/engine/pyfluid/aabb.py | 2 +- src/engine/pyfluid/array3d.py | 2 +- src/engine/pyfluid/fluidsimulation.py | 98 ++- src/engine/pyfluid/forcefield.py | 2 +- src/engine/pyfluid/forcefieldcurve.py | 2 +- src/engine/pyfluid/forcefieldgrid.py | 2 +- src/engine/pyfluid/forcefieldpoint.py | 2 +- src/engine/pyfluid/forcefieldsurface.py | 2 +- src/engine/pyfluid/forcefieldvolume.py | 2 +- src/engine/pyfluid/gpu_utils.py | 2 +- src/engine/pyfluid/gridindex.py | 2 +- src/engine/pyfluid/meshfluidsource.py | 2 +- src/engine/pyfluid/meshobject.py | 2 +- src/engine/pyfluid/method_decorators.py | 2 +- src/engine/pyfluid/pybindings.py | 2 +- src/engine/pyfluid/pyfluid.py | 4 +- src/engine/pyfluid/trianglemesh.py | 6 +- src/engine/pyfluid/vector3.py | 2 +- src/engine/scalarfield.cpp | 2 +- src/engine/scalarfield.h | 2 +- src/engine/spatialpointgrid.cpp | 2 +- src/engine/spatialpointgrid.h | 2 +- src/engine/stopwatch.cpp | 2 +- src/engine/stopwatch.h | 2 +- src/engine/subdividedarray3d.h | 2 +- src/engine/threadutils.cpp | 2 +- src/engine/threadutils.h | 2 +- src/engine/triangle.h | 2 +- src/engine/trianglemesh.cpp | 2 +- src/engine/trianglemesh.h | 2 +- src/engine/turbulencefield.cpp | 2 +- src/engine/turbulencefield.h | 2 +- src/engine/velocityadvector.cpp | 228 +++++- src/engine/velocityadvector.h | 45 +- src/engine/versionutils.cpp.in | 2 +- src/engine/versionutils.h | 2 +- src/engine/viscositysolver.cpp | 183 ++--- src/engine/viscositysolver.h | 30 +- src/engine/vmath.cpp | 2 +- src/engine/vmath.h | 2 +- 245 files changed, 3480 insertions(+), 1051 deletions(-) create mode 100644 src/engine/particlesystem.cpp create mode 100644 src/engine/particlesystem.h diff --git a/LICENSE_MIT.md b/LICENSE_MIT.md index 9d4c27b7..8296ddc9 100644 --- a/LICENSE_MIT.md +++ b/LICENSE_MIT.md @@ -1,4 +1,4 @@ -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 2c96360d..f4f89a0f 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Want to try FLIP Fluids addon before buying the full [Blender Market Product](ht ### Getting Started -Download the latest FLIP Fluids Demo installation file here: [FLIP_Fluids_addon_0.0.9a_demo_03_feb_2021.zip](https://github.com/rlguy/Blender-FLIP-Fluids/releases/download/v0.0.9/FLIP_Fluids_addon_0.0.9a_demo_03_nov_2021.zip) +Download the latest FLIP Fluids Demo installation file here: [FLIP_Fluids_addon_0.0.9b_demo_03_feb_2021.zip](https://github.com/rlguy/Blender-FLIP-Fluids/releases/download/v0.0.9/FLIP_Fluids_addon_0.0.9b_demo_06_apr_2021.zip) After downloading the demo addon, follow our [Installation Instructions](https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Addon-Installation-and-Uninstallation). The instructions are similar to installing any other Blender addon. @@ -16,4 +16,4 @@ Get started creating your first simulation with our [beginners guide](https://gi ### Have any questions? -Feel free to send us a message on the [Blender Market](https://blendermarket.com/products/flipfluids), or send us an email at support@flipfluids.com. We're always glad to help! +Feel free to send us a message on the [Blender Market](https://blendermarket.com/products/flipfluids), or send us an email at support@flipfluids.com. We're always glad to help! \ No newline at end of file diff --git a/__init__.py b/__init__.py index a8008613..53d10d7d 100644 --- a/__init__.py +++ b/__init__.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/build.py b/build.py index 3fa006ce..a73551bf 100644 --- a/build.py +++ b/build.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 496dd537..a853ae64 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -47,13 +47,13 @@ set(CMAKE_BUILD_TYPE Release) set(FLUIDENGINE_VERSION_MAJOR 0) set(FLUIDENGINE_VERSION_MINOR 0) set(FLUIDENGINE_VERSION_REVISION 9) -set(FLUIDENGINE_VERSION_LABEL "0.0.9a Demo 03-FEB-2021") +set(FLUIDENGINE_VERSION_LABEL "0.0.9b Demo 06-APR-2021") if(BUILD_DEBUG) set(FLUIDENGINE_VERSION_LABEL "${FLUIDENGINE_VERSION_LABEL} (DEBUG BUILD)") endif() -message(STATUS "FLIP Fluids verson ${FLUIDENGINE_VERSION_LABEL}") +message(STATUS "FLIP Fluids version ${FLUIDENGINE_VERSION_LABEL}") if(BUILD_DEBUG) message(STATUS "Building in debug mode") else() diff --git a/src/addon/__init__.py.in b/src/addon/__init__.py.in index c402669d..5baa781a 100644 --- a/src/addon/__init__.py.in +++ b/src/addon/__init__.py.in @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -99,14 +99,7 @@ def render_cancel(scene): @bpy.app.handlers.persistent def frame_change_pre(scene, depsgraph=None): - #scene.objects["mesh_cache"].modifiers["Ocean"].time = scene.objects["mesh_cache"].evaluated_get(depsgraph).modifiers["Ocean"].time - - dprops = scene.flip_fluid.get_domain_properties() - domain_object = scene.flip_fluid.get_domain_object() - if domain_object is not None: - domain_object_eval = domain_object.evaluated_get(bpy.context.evaluated_depsgraph_get()) - dprops_eval = domain_object_eval.flip_fluid.domain - dprops.render.override_frame = dprops_eval.render.override_frame + pass @bpy.app.handlers.persistent diff --git a/src/addon/bake.py b/src/addon/bake.py index 59d58b0c..2d80874f 100644 --- a/src/addon/bake.py +++ b/src/addon/bake.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -431,7 +431,7 @@ def __extract_curve_mesh(object_name, frameno=0): def __extract_data(data_filepath): - with open(data_filepath, 'r') as f: + with open(data_filepath, 'r', encoding='utf-8') as f: json_data = json.loads(f.read()) data = flip_fluid_map.Map(json_data) return data @@ -538,7 +538,7 @@ def __write_save_state_file_data(file_data_path, data, is_appending_data=False): f.write(data) -def __load_save_state_marker_particle_data(fluidsim, save_state_directory, autosave_info): +def __load_save_state_marker_particle_data(fluidsim, save_state_directory, autosave_info, data): num_particles = autosave_info['num_marker_particles'] if num_particles == 0: return @@ -547,6 +547,23 @@ def __load_save_state_marker_particle_data(fluidsim, save_state_directory, autos position_data_file = os.path.join(d, autosave_info['marker_particle_position_filedata']) velocity_data_file = os.path.join(d, autosave_info['marker_particle_velocity_filedata']) + velocity_transfer_method = data.domain_data.advanced.velocity_transfer_method.data + is_apic_enabled = velocity_transfer_method == 'VELOCITY_TRANSFER_METHOD_APIC' + load_apic_data = False + if is_apic_enabled: + is_apic_data_available = ('marker_particle_affinex_filedata' in autosave_info and + 'marker_particle_affiney_filedata' in autosave_info and + 'marker_particle_affinez_filedata' in autosave_info) + is_apic_data_available = (is_apic_data_available and + autosave_info['marker_particle_affinex_filedata'] and + autosave_info['marker_particle_affiney_filedata'] and + autosave_info['marker_particle_affinez_filedata']) + if is_apic_data_available: + affinex_data_file = os.path.join(d, autosave_info['marker_particle_affinex_filedata']) + affiney_data_file = os.path.join(d, autosave_info['marker_particle_affiney_filedata']) + affinez_data_file = os.path.join(d, autosave_info['marker_particle_affinez_filedata']) + load_apic_data = True + particles_per_read = 2**21 bytes_per_vector = 12 max_byte = bytes_per_vector * num_particles @@ -560,6 +577,12 @@ def __load_save_state_marker_particle_data(fluidsim, save_state_directory, autos velocity_data = __read_save_state_file_data(velocity_data_file, start_byte, end_byte) fluidsim.load_marker_particle_data(particle_count, position_data, velocity_data) + if load_apic_data: + affinex_data = __read_save_state_file_data(affinex_data_file, start_byte, end_byte) + affiney_data = __read_save_state_file_data(affiney_data_file, start_byte, end_byte) + affinez_data = __read_save_state_file_data(affinez_data_file, start_byte, end_byte) + fluidsim.load_marker_particle_affine_data(particle_count, affinex_data, affiney_data, affinez_data) + def __load_save_state_diffuse_particle_data(fluidsim, save_state_directory, autosave_info): num_particles = autosave_info['num_diffuse_particles'] @@ -615,13 +638,20 @@ def __load_save_state_simulator_data(fluidsim, autosave_info): def __delete_outdated_savestates(cache_directory, savestate_id): savestate_directory = os.path.join(cache_directory, "savestates") - subdirs = os.listdir(savestate_directory) + subdirs = [d for d in os.listdir(savestate_directory) if os.path.isdir(os.path.join(savestate_directory, d)) ] if "autosave" in subdirs: subdirs.remove("autosave") + extensions = [".state", ".data"] for d in subdirs: - extensions = [".state", ".data"] - if int(d[-6:]) > savestate_id: + try: + savestate_number = int(d[-6:]) + if savestate_number < 0: + continue + except ValueError: + continue + + if savestate_number > savestate_id: path = os.path.join(savestate_directory, d) try: fpl.delete_files_in_directory(path, extensions, remove_directory=True) @@ -643,7 +673,7 @@ def __delete_outdated_meshes(cache_directory, savestate_id): print("Error: unable to delete file <" + path + "> (skipping)") stats_filepath = os.path.join(cache_directory, "flipstats.data") - with open(stats_filepath, 'r') as f: + with open(stats_filepath, 'r', encoding='utf-8') as f: stats_info = json.loads(f.read()) for key in stats_info.copy().keys(): @@ -651,7 +681,7 @@ def __delete_outdated_meshes(cache_directory, savestate_id): del stats_info[key] stats_json = json.dumps(stats_info, sort_keys=True, indent=4) - with open(stats_filepath, 'w') as f: + with open(stats_filepath, 'w', encoding='utf-8') as f: f.write(stats_json) @@ -672,10 +702,10 @@ def __load_save_state_data(fluidsim, data, cache_directory, savestate_id): if not os.path.isfile(autosave_info_file): return - with open(autosave_info_file, 'r') as f: + with open(autosave_info_file, 'r', encoding='utf-8') as f: autosave_info = json.loads(f.read()) - __load_save_state_marker_particle_data(fluidsim, autosave_directory, autosave_info) + __load_save_state_marker_particle_data(fluidsim, autosave_directory, autosave_info, data) __load_save_state_diffuse_particle_data(fluidsim, autosave_directory, autosave_info) __load_save_state_simulator_data(fluidsim, autosave_info) @@ -859,6 +889,9 @@ def __initialize_fluid_simulation_settings(fluidsim, data): if is_viscosity_enabled: fluidsim.viscosity = __get_viscosity_value(world, frameno) + tolerance_int = __get_parameter_data(world.viscosity_solver_error_tolerance, frameno) + fluidsim.viscosity_solver_error_tolerance = 1.0 * 10.0**(-tolerance_int) + is_surface_tension_enabled = __get_parameter_data(world.enable_surface_tension, frameno) if is_surface_tension_enabled: surface_tension = __get_surface_tension_value(world, frameno) @@ -937,7 +970,14 @@ def __initialize_fluid_simulation_settings(fluidsim, data): fluidsim.jitter_surface_marker_particles = \ __get_parameter_data(advanced.jitter_surface_particles, frameno) + velocity_transfer_method = __get_parameter_data(advanced.velocity_transfer_method, frameno) + if velocity_transfer_method == 'VELOCITY_TRANSFER_METHOD_FLIP': + fluidsim.set_velocity_transfer_method_FLIP() + elif velocity_transfer_method == 'VELOCITY_TRANSFER_METHOD_APIC': + fluidsim.set_velocity_transfer_method_APIC() + fluidsim.PICFLIP_ratio = __get_parameter_data(advanced.PICFLIP_ratio, frameno) + fluidsim.PICAPIC_ratio = __get_parameter_data(advanced.PICAPIC_ratio, frameno) CFL_number = __get_parameter_data(advanced.CFL_condition_number, frameno) fluidsim.CFL_condition_number = CFL_number @@ -1585,6 +1625,10 @@ def __update_animatable_domain_properties(fluidsim, data, frameno): if is_viscosity_enabled: viscosity = __get_viscosity_value(world, frameno) __set_property(fluidsim, 'viscosity', viscosity) + + tolerance_int = __get_parameter_data(world.viscosity_solver_error_tolerance, frameno) + error_tolerance = 1.0 * 10.0**(-tolerance_int) + __set_property(fluidsim, 'viscosity_solver_error_tolerance', error_tolerance) elif fluidsim.viscosity > 0.0: __set_property(fluidsim, 'viscosity', 0.0) @@ -1676,6 +1720,9 @@ def __update_animatable_domain_properties(fluidsim, data, frameno): PICFLIP_ratio = __get_parameter_data(advanced.PICFLIP_ratio, frameno) __set_property(fluidsim, 'PICFLIP_ratio', PICFLIP_ratio) + PICAPIC_ratio = __get_parameter_data(advanced.PICAPIC_ratio, frameno) + __set_property(fluidsim, 'PICAPIC_ratio', PICAPIC_ratio) + CFL_number = __get_parameter_data(advanced.CFL_condition_number, frameno) __set_property(fluidsim, 'CFL_condition_number', CFL_number) @@ -1750,7 +1797,7 @@ def __write_bounds_data(cache_directory, fluidsim, frameno): bounds_filename = "bounds" + fstring + ".bbox" bounds_filepath = os.path.join(cache_directory, "bakefiles", bounds_filename) bounds_json = json.dumps(bounds) - with open(bounds_filepath, 'w') as f: + with open(bounds_filepath, 'w', encoding='utf-8') as f: f.write(bounds_json) @@ -1863,7 +1910,7 @@ def __write_force_field_debug_data(cache_directory, fluidsim, frameno): def __write_logfile_data(cache_directory, logfile_name, fluidsim): filedata = fluidsim.get_logfile_data() logpath = os.path.join(cache_directory, "logs", logfile_name) - with open(logpath, 'a') as f: + with open(logpath, 'a', encoding='utf-8') as f: f.write(filedata) @@ -1925,7 +1972,7 @@ def __write_frame_stats_data(cache_directory, fluidsim, frameno): cstats = fluidsim.get_frame_stats_data() stats = __get_frame_stats_dict(cstats) filedata = json.dumps(stats, sort_keys=True, indent=4) - with open(statspath, 'w') as f: + with open(statspath, 'w', encoding='utf-8') as f: f.write(filedata) @@ -1936,6 +1983,10 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno): position_data_path = os.path.join(autosave_dir, "marker_particle_position.data") velocity_data_path = os.path.join(autosave_dir, "marker_particle_velocity.data") + affinex_data_path = os.path.join(autosave_dir, "marker_particle_affinex.data") + affiney_data_path = os.path.join(autosave_dir, "marker_particle_affiney.data") + affinez_data_path = os.path.join(autosave_dir, "marker_particle_affinez.data") + diffuse_position_data_path = os.path.join(autosave_dir, "diffuse_particle_position.data") diffuse_velocity_data_path = os.path.join(autosave_dir, "diffuse_particle_velocity.data") diffuse_lifetime_data_path = os.path.join(autosave_dir, "diffuse_particle_lifetime.data") @@ -1949,6 +2000,11 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno): velocity_data_path, autosave_info_path ] + autosave_apic_filepaths = [ + affinex_data_path, + affiney_data_path, + affinez_data_path + ] autosave_diffuse_filepaths = [ diffuse_position_data_path, diffuse_velocity_data_path, @@ -1958,12 +2014,12 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno): ] num_particles = fluidsim.get_num_marker_particles() - particles_per_write = 2**21 - num_writes = (num_particles // particles_per_write) + 1 + marker_particles_per_write = 2**21 + num_marker_particle_writes = (num_particles // marker_particles_per_write) + 1 try: - for i in range(num_writes): - start_idx = i * particles_per_write - end_idx = min((i + 1) * particles_per_write, num_particles) + for i in range(num_marker_particle_writes): + start_idx = i * marker_particles_per_write + end_idx = min((i + 1) * marker_particles_per_write, num_particles) is_appending = i != 0 data = fluidsim.get_marker_particle_position_data_range(start_idx, end_idx) @@ -1971,13 +2027,21 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno): data = fluidsim.get_marker_particle_velocity_data_range(start_idx, end_idx) __write_save_state_file_data(velocity_data_path + temp_extension, data, is_appending_data=is_appending) + if fluidsim.is_velocity_transfer_method_APIC(): + data = fluidsim.get_marker_particle_affinex_data_range(start_idx, end_idx) + __write_save_state_file_data(affinex_data_path + temp_extension, data, is_appending_data=is_appending) + data = fluidsim.get_marker_particle_affiney_data_range(start_idx, end_idx) + __write_save_state_file_data(affiney_data_path + temp_extension, data, is_appending_data=is_appending) + data = fluidsim.get_marker_particle_affinez_data_range(start_idx, end_idx) + __write_save_state_file_data(affinez_data_path + temp_extension, data, is_appending_data=is_appending) + if fluidsim.get_num_diffuse_particles() > 0: num_particles = fluidsim.get_num_diffuse_particles() - particles_per_write = 2**21 - num_writes = (num_particles // particles_per_write) + 1 - for i in range(num_writes): - start_idx = i * particles_per_write - end_idx = min((i + 1) * particles_per_write, num_particles) + diffuse_particles_per_write = 2**21 + num_diffuse_particle_writes = (num_particles // diffuse_particles_per_write) + 1 + for i in range(num_diffuse_particle_writes): + start_idx = i * diffuse_particles_per_write + end_idx = min((i + 1) * diffuse_particles_per_write, num_particles) is_appending = i != 0 data = fluidsim.get_diffuse_particle_position_data_range(start_idx, end_idx) @@ -2009,21 +2073,31 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno): autosave_info['marker_particle_velocity_filedata'] = "marker_particle_velocity.data" autosave_info['num_diffuse_particles'] = fluidsim.get_num_diffuse_particles() + autosave_info['marker_particle_affinex_filedata'] = "" + autosave_info['marker_particle_affiney_filedata'] = "" + autosave_info['marker_particle_affinez_filedata'] = "" + + autosave_info['diffuse_particle_position_filedata'] = "" + autosave_info['diffuse_particle_velocity_filedata'] = "" + autosave_info['diffuse_particle_lifetime_filedata'] = "" + autosave_info['diffuse_particle_type_filedata'] = "" + autosave_info['diffuse_particle_id_filedata'] = "" + + if fluidsim.is_velocity_transfer_method_APIC(): + autosave_info['marker_particle_affinex_filedata'] = "marker_particle_affinex.data" + autosave_info['marker_particle_affiney_filedata'] = "marker_particle_affiney.data" + autosave_info['marker_particle_affinez_filedata'] = "marker_particle_affinez.data" + if fluidsim.get_num_diffuse_particles() > 0: autosave_info['diffuse_particle_position_filedata'] = "diffuse_particle_position.data" autosave_info['diffuse_particle_velocity_filedata'] = "diffuse_particle_velocity.data" autosave_info['diffuse_particle_lifetime_filedata'] = "diffuse_particle_lifetime.data" autosave_info['diffuse_particle_type_filedata'] = "diffuse_particle_type.data" autosave_info['diffuse_particle_id_filedata'] = "diffuse_particle_id.data" - else: - autosave_info['diffuse_particle_position_filedata'] = "" - autosave_info['diffuse_particle_velocity_filedata'] = "" - autosave_info['diffuse_particle_lifetime_filedata'] = "" - autosave_info['diffuse_particle_type_filedata'] = "" - autosave_info['diffuse_particle_id_filedata'] = "" + autosave_json = json.dumps(autosave_info, sort_keys=True, indent=4) - with open(autosave_info_path + temp_extension, 'w') as f: + with open(autosave_info_path + temp_extension, 'w', encoding='utf-8') as f: f.write(autosave_json) except Exception as e: print("FLIP Fluids: OS/Filesystem Error: Unable to write autosave files to storage") @@ -2032,10 +2106,9 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno): return try: - for filepath in autosave_default_filepaths: - fpl.delete_file(filepath) - if fluidsim.get_num_diffuse_particles() > 0: - for filepath in autosave_diffuse_filepaths: + data_filepaths = autosave_default_filepaths + autosave_apic_filepaths + autosave_diffuse_filepaths + for filepath in data_filepaths: + if os.path.isfile(filepath): fpl.delete_file(filepath) except Exception as e: print("FLIP Fluids: OS/Filesystem Error: Unable to delete older autosave files from storage") @@ -2046,6 +2119,9 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno): try: for filepath in autosave_default_filepaths: os.rename(filepath + temp_extension, filepath) + if fluidsim.is_velocity_transfer_method_APIC(): + for filepath in autosave_apic_filepaths: + os.rename(filepath + temp_extension, filepath) if fluidsim.get_num_diffuse_particles() > 0: for filepath in autosave_diffuse_filepaths: os.rename(filepath + temp_extension, filepath) diff --git a/src/addon/exit_handler.py b/src/addon/exit_handler.py index 14697194..b79a00ea 100644 --- a/src/addon/exit_handler.py +++ b/src/addon/exit_handler.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/export.py b/src/addon/export.py index bfc2e416..0bccfeb8 100644 --- a/src/addon/export.py +++ b/src/addon/export.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -39,7 +39,7 @@ def __export_simulation_data_to_file(context, simobjects, filename): jsonstr = json.dumps(data, sort_keys=True, indent=4, separators=(',', ': ')) os.makedirs(os.path.dirname(filename), exist_ok=True) - with open(filename, "w") as f: + with open(filename, 'w', encoding='utf-8') as f: f.write(jsonstr) @@ -218,7 +218,7 @@ def __export_static_mesh_data(object_data, mesh_directory): info = {'mesh_type': 'STATIC'} info_json = json.dumps(info, sort_keys=True) info_filepath = os.path.join(mesh_directory, "mesh.info") - with open(info_filepath, "w") as f: + with open(info_filepath, 'w', encoding='utf-8') as f: f.write(info_json) dprops = __get_domain_properties() @@ -242,7 +242,7 @@ def __export_keyframed_mesh_data(object_data, mesh_directory): matrix_data = object_data['data']['matrix_data'] matrix_json = json.dumps(matrix_data) matrix_filepath = os.path.join(mesh_directory, "transforms.data") - with open(matrix_filepath, "w") as f: + with open(matrix_filepath, 'w', encoding='utf-8') as f: f.write(matrix_json) info = { @@ -252,7 +252,7 @@ def __export_keyframed_mesh_data(object_data, mesh_directory): } info_json = json.dumps(info, sort_keys=True) info_filepath = os.path.join(mesh_directory, "mesh.info") - with open(info_filepath, "w") as f: + with open(info_filepath, 'w', encoding='utf-8') as f: f.write(info_json) matrix_filesize = os.stat(matrix_filepath).st_size @@ -304,7 +304,7 @@ def __export_animated_mesh_data(object_data, mesh_directory): } info_json = json.dumps(info, sort_keys=True) info_filepath = os.path.join(mesh_directory, "mesh.info") - with open(info_filepath, "w") as f: + with open(info_filepath, 'w', encoding='utf-8') as f: f.write(info_json) object_data['data']['mesh_data'] = [] diff --git a/src/addon/filesystem/__init__.py b/src/addon/filesystem/__init__.py index 456b4cf2..d51e6583 100644 --- a/src/addon/filesystem/__init__.py +++ b/src/addon/filesystem/__init__.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/filesystem/filesystem_protection_layer.py b/src/addon/filesystem/filesystem_protection_layer.py index 7d669d9b..725f7d64 100644 --- a/src/addon/filesystem/filesystem_protection_layer.py +++ b/src/addon/filesystem/filesystem_protection_layer.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -64,7 +64,12 @@ def get_directory_whitelist(): def path_is_parent(parent_path, child_path): parent_path = os.path.abspath(parent_path) child_path = os.path.abspath(child_path) - return os.path.commonpath([parent_path]) == os.path.commonpath([parent_path, child_path]) + try: + parent_child_commonpath = os.path.commonpath([parent_path, child_path]) + except ValueError: + # paths not on same drive + return False + return os.path.commonpath([parent_path]) == parent_child_commonpath def check_extensions_valid(extensions): diff --git a/src/addon/materials/__init__.py b/src/addon/materials/__init__.py index 01ed0231..6bca2ebe 100644 --- a/src/addon/materials/__init__.py +++ b/src/addon/materials/__init__.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/materials/material_library.py b/src/addon/materials/material_library.py index f0258eb0..ecfa8739 100644 --- a/src/addon/materials/material_library.py +++ b/src/addon/materials/material_library.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/objects/__init__.py b/src/addon/objects/__init__.py index 28ce0773..0bd0b947 100644 --- a/src/addon/objects/__init__.py +++ b/src/addon/objects/__init__.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/objects/flip_fluid_aabb.py b/src/addon/objects/flip_fluid_aabb.py index c6ca200b..c6d31c59 100644 --- a/src/addon/objects/flip_fluid_aabb.py +++ b/src/addon/objects/flip_fluid_aabb.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/objects/flip_fluid_cache.py b/src/addon/objects/flip_fluid_cache.py index fa7d4ede..a76fc09d 100644 --- a/src/addon/objects/flip_fluid_cache.py +++ b/src/addon/objects/flip_fluid_cache.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -175,6 +175,11 @@ def initialize_cache_object(self): smooth_mod = cache_object.modifiers.new("Smooth", "SMOOTH") smooth_mod.iterations = 0 + # Motion blur not supported. Leaving motion blur enabled can cause + # slow render in versions of Blender 2.91+. Workaround is to + # automatically disable motion blur on the object. + cache_object.cycles.use_motion_blur = False + self._initialize_cache_object_octane(cache_object) self.cache_object = cache_object @@ -464,6 +469,11 @@ def initialize_duplivert_object(self, vertices=[], polygons=[], scale=1.0, insta vcu.set_object_instance_type(cache_object, instance_type) vcu.set_object_hide_viewport(duplivert_object, True) + # Motion blur not supported. Leaving motion blur enabled can cause + # slow render in versions of Blender 2.91+. Workaround is to + # automatically disable motion blur on the object. + duplivert_object.cycles.use_motion_blur = False + self.duplivert_object = duplivert_object @@ -792,7 +802,7 @@ def _initialize_bounds_data(self, frameno): filepath = self._get_bounds_filepath(frameno) bounds_data = None if os.path.isfile(filepath): - with open(filepath, 'r') as f: + with open(filepath, 'r', encoding='utf-8') as f: bounds_data = json.loads(f.read()) self.bounds.set(bounds_data) diff --git a/src/addon/objects/flip_fluid_geometry_database.py b/src/addon/objects/flip_fluid_geometry_database.py index a836ffd7..a7a10f98 100644 --- a/src/addon/objects/flip_fluid_geometry_database.py +++ b/src/addon/objects/flip_fluid_geometry_database.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/objects/flip_fluid_geometry_export_object.py b/src/addon/objects/flip_fluid_geometry_export_object.py index 143fa422..92d81409 100644 --- a/src/addon/objects/flip_fluid_geometry_export_object.py +++ b/src/addon/objects/flip_fluid_geometry_export_object.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/objects/flip_fluid_geometry_exporter.py b/src/addon/objects/flip_fluid_geometry_exporter.py index b96ebe92..bd210ad9 100644 --- a/src/addon/objects/flip_fluid_geometry_exporter.py +++ b/src/addon/objects/flip_fluid_geometry_exporter.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/objects/flip_fluid_map.py b/src/addon/objects/flip_fluid_map.py index dddeb5b0..704452db 100644 --- a/src/addon/objects/flip_fluid_map.py +++ b/src/addon/objects/flip_fluid_map.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/objects/flip_fluid_material_library.py b/src/addon/objects/flip_fluid_material_library.py index a6ee447a..b92fd4e7 100644 --- a/src/addon/objects/flip_fluid_material_library.py +++ b/src/addon/objects/flip_fluid_material_library.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -208,7 +208,7 @@ def _initialize_library_material_list(self): description_path = f[:-len(extension)] + "description" description_text = "" if os.path.isfile(description_path): - with open(description_path, 'r') as description_file: + with open(description_path, 'r', encoding='utf-8') as description_file: description_text = description_file.read() new_material = self.material_list.add() @@ -239,12 +239,12 @@ def _update_material_library_hash(self): icon_hash_path = os.path.join(icon_dir, "material_library_hash") old_material_library_hash = None if os.path.isfile(icon_hash_path): - with open(icon_hash_path, "r") as f: + with open(icon_hash_path, 'r', encoding='utf-8') as f: old_material_library_hash = f.read() current_material_library_hash = self._calculate_material_library_hash() if current_material_library_hash != old_material_library_hash: - with open(icon_hash_path, "w") as f: + with open(icon_hash_path, 'w', encoding='utf-8') as f: f.write(current_material_library_hash) return True diff --git a/src/addon/objects/flip_fluid_preset_stack.py b/src/addon/objects/flip_fluid_preset_stack.py index 84a60fc2..f51afc25 100644 --- a/src/addon/objects/flip_fluid_preset_stack.py +++ b/src/addon/objects/flip_fluid_preset_stack.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/operators/__init__.py b/src/addon/operators/__init__.py index cace0d77..072649c2 100644 --- a/src/addon/operators/__init__.py +++ b/src/addon/operators/__init__.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/operators/bake_operators.py b/src/addon/operators/bake_operators.py index 028792cc..79894e38 100644 --- a/src/addon/operators/bake_operators.py +++ b/src/addon/operators/bake_operators.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -45,7 +45,7 @@ def _update_stats(context): cache_dir = dprops.cache.get_cache_abspath() statsfilepath = os.path.join(cache_dir, dprops.stats.stats_filename) if not os.path.isfile(statsfilepath): - with open(statsfilepath, 'w') as f: + with open(statsfilepath, 'w', encoding='utf-8') as f: f.write(json.dumps({}, sort_keys=True, indent=4)) temp_dir = os.path.join(cache_dir, "temp") @@ -54,13 +54,13 @@ def _update_stats(context): if not stat_files: return - with open(statsfilepath, 'r') as f: + with open(statsfilepath, 'r', encoding='utf-8') as f: stats_dict = json.loads(f.read()) for statpath in stat_files: filename = os.path.basename(statpath) frameno = int(filename[len("framestats"):-len(".data")]) - with open(statpath, 'r') as frame_stats: + with open(statpath, 'r', encoding='utf-8') as frame_stats: try: frame_stats_dict = json.loads(frame_stats.read()) except: @@ -71,7 +71,7 @@ def _update_stats(context): stats_dict[str(frameno)] = frame_stats_dict fpl.delete_file(statpath) - with open(statsfilepath, 'w') as f: + with open(statsfilepath, 'w', encoding='utf-8') as f: f.write(json.dumps(stats_dict, sort_keys=True, indent=4)) dprops.stats.is_stats_current = False @@ -539,6 +539,17 @@ def _clear_cache(self, context): ) + def _reset_property_data(self): + dprops = bpy.context.scene.flip_fluid.get_domain_properties() + dprops.mesh_cache.reset_cache_objects() + dprops.stats.refresh_stats() + dprops.stats.reset_time_remaining() + dprops.stats.reset_stats_values() + dprops.bake.check_autosave() + dprops.render.reset_bake() + + + @classmethod def poll(cls, context): dprops = bpy.context.scene.flip_fluid.get_domain_properties() @@ -551,21 +562,15 @@ def execute(self, context): dprops = bpy.context.scene.flip_fluid.get_domain_properties() cache_path = dprops.cache.get_cache_abspath() if not os.path.isdir(cache_path): - self.report({"ERROR"}, "Current cache directory does not exist") - return {'CANCELLED'} - dprops.cache.mark_cache_directory_set() + self._reset_property_data() + self.report({"INFO"}, "Current cache directory does not exist - skipping cache reset") + return {'FINISHED'} + dprops.cache.mark_cache_directory_set() self._clear_cache(context) - dprops.mesh_cache.reset_cache_objects() - - self.report({"INFO"}, "Successfully reset bake") - - dprops.stats.refresh_stats() - dprops.stats.reset_time_remaining() - dprops.stats.reset_stats_values() - dprops.bake.check_autosave() - dprops.render.reset_bake() + self._reset_property_data() + self.report({"INFO"}, "Successfully reset bake") return {'FINISHED'} diff --git a/src/addon/operators/cache_operators.py b/src/addon/operators/cache_operators.py index 2dd35a81..21d55e96 100644 --- a/src/addon/operators/cache_operators.py +++ b/src/addon/operators/cache_operators.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -451,9 +451,17 @@ def execute(self, context): def register(): bpy.utils.register_class(FlipFluidFreeCache) bpy.utils.register_class(FlipFluidFreeUnheldCacheFiles) + + # The move, rename, and copy cache operations should not be performed + # in Blender and are removed from the UI. There is a potential for Blender + # to crash, which could lead to loss of data. It is best to perform these + # operations through the OS filesystem which is cabable of handling failures. + """ bpy.utils.register_class(FlipFluidMoveCache) bpy.utils.register_class(FlipFluidRenameCache) bpy.utils.register_class(FlipFluidCopyCache) + """ + bpy.utils.register_class(FlipFluidRelativeCacheDirectory) bpy.utils.register_class(FlipFluidAbsoluteCacheDirectory) bpy.utils.register_class(FlipFluidRelativeLinkedGeometryDirectory) @@ -464,9 +472,13 @@ def register(): def unregister(): bpy.utils.unregister_class(FlipFluidFreeCache) bpy.utils.unregister_class(FlipFluidFreeUnheldCacheFiles) + + """ bpy.utils.unregister_class(FlipFluidMoveCache) bpy.utils.unregister_class(FlipFluidRenameCache) bpy.utils.unregister_class(FlipFluidCopyCache) + """ + bpy.utils.unregister_class(FlipFluidRelativeCacheDirectory) bpy.utils.unregister_class(FlipFluidAbsoluteCacheDirectory) bpy.utils.unregister_class(FlipFluidRelativeLinkedGeometryDirectory) diff --git a/src/addon/operators/draw_force_field_operators.py b/src/addon/operators/draw_force_field_operators.py index e49b3081..1400db42 100644 --- a/src/addon/operators/draw_force_field_operators.py +++ b/src/addon/operators/draw_force_field_operators.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -22,6 +22,7 @@ from ..objects.flip_fluid_aabb import AABB from ..utils import ui_utils from ..utils import version_compatibility_utils as vcu +from .. import render if vcu.is_blender_28(): import gpu @@ -33,6 +34,11 @@ particle_shader = None particle_batch_draw = None def update_debug_force_field_geometry(context): + if render.is_rendering(): + # This method does not need to be run while rendering. Can cause + # crashes on certain systems. + return + global particle_vertices global particle_vertex_colors particle_vertices = [] @@ -42,6 +48,9 @@ def update_debug_force_field_geometry(context): if dprops is None or not dprops.debug.export_force_field: return + if not dprops.debug.force_field_visibility: + return + ffdata = dprops.mesh_cache.gl_force_field.get_force_field_data() if ffdata is None or ffdata['vertices'] is None: return @@ -84,7 +93,6 @@ def update_debug_force_field_geometry(context): vertex_shader = """ uniform mat4 ModelViewProjectionMatrix; - uniform float pointsize; in vec3 pos; in vec4 color; @@ -93,7 +101,6 @@ def update_debug_force_field_geometry(context): void main() { - gl_PointSize = pointsize; gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); finalColor = color; } @@ -110,7 +117,6 @@ def update_debug_force_field_geometry(context): """ particle_shader = gpu.types.GPUShader(vertex_shader, fragment_shader) - particle_shader.uniform_float('pointsize', dprops.debug.force_field_line_size) particle_batch_draw = batch_for_shader( particle_shader, 'POINTS', {"pos": particle_vertices, "color": particle_vertex_colors}, @@ -148,6 +154,11 @@ def poll(cls, context): def draw_callback_3d(self, context): + if render.is_rendering(): + # This method does not need to be run while rendering. Can cause + # crashes on certain systems. + return + global particle_vertices global particle_vertex_colors @@ -156,6 +167,9 @@ def draw_callback_3d(self, context): if domain is None or len(particle_vertices) == 0: return + if not dprops.debug.force_field_visibility: + return + if vcu.get_object_hide_viewport(domain): return diff --git a/src/addon/operators/draw_grid_operators.py b/src/addon/operators/draw_grid_operators.py index 4824dcb0..30085934 100644 --- a/src/addon/operators/draw_grid_operators.py +++ b/src/addon/operators/draw_grid_operators.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -22,6 +22,7 @@ from ..objects.flip_fluid_aabb import AABB from ..utils import ui_utils from ..utils import version_compatibility_utils as vcu +from .. import render if vcu.is_blender_28(): import gpu @@ -33,6 +34,11 @@ z_coords = [] bounds_coords = [] def update_debug_grid_geometry(context): + if render.is_rendering(): + # This method does not need to be run while rendering. Can cause + # crashes on certain systems. + return + global x_coords global y_coords global z_coords @@ -159,6 +165,11 @@ def poll(cls, context): def draw_callback_2d(self, context): + if render.is_rendering(): + # This method does not need to be run while rendering. Can cause + # crashes on certain systems. + return + domain = context.scene.flip_fluid.get_domain_object() if domain is None: return @@ -311,6 +322,11 @@ def draw_callback_2d(self, context): def draw_callback_3d(self, context): + if render.is_rendering(): + # This method does not need to be run while rendering. Can cause + # crashes on certain systems. + return + global x_coords global y_coords global z_coords diff --git a/src/addon/operators/draw_particles_operators.py b/src/addon/operators/draw_particles_operators.py index 2c228e26..14839646 100644 --- a/src/addon/operators/draw_particles_operators.py +++ b/src/addon/operators/draw_particles_operators.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -22,6 +22,7 @@ from ..objects.flip_fluid_aabb import AABB from ..utils import ui_utils from ..utils import version_compatibility_utils as vcu +from .. import render if vcu.is_blender_28(): import gpu @@ -33,6 +34,11 @@ particle_shader = None particle_batch_draw = None def update_debug_particle_geometry(context): + if render.is_rendering(): + # This method does not need to be run while rendering. Can cause + # crashes on certain systems. + return + global particle_vertices global particle_vertex_colors @@ -40,6 +46,9 @@ def update_debug_particle_geometry(context): if dprops is None or not dprops.debug.export_fluid_particles: return + if not dprops.debug.fluid_particles_visibility: + return + particle_vertices = [] particle_vertex_colors = [] pdata = dprops.mesh_cache.gl_particles.get_point_cache_data() @@ -83,7 +92,6 @@ def update_debug_particle_geometry(context): vertex_shader = """ uniform mat4 ModelViewProjectionMatrix; - uniform float pointsize; in vec3 pos; in vec4 color; @@ -92,7 +100,6 @@ def update_debug_particle_geometry(context): void main() { - gl_PointSize = pointsize; gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); finalColor = color; } @@ -109,7 +116,6 @@ def update_debug_particle_geometry(context): """ particle_shader = gpu.types.GPUShader(vertex_shader, fragment_shader) - particle_shader.uniform_float('pointsize', dprops.debug.particle_size) particle_batch_draw = batch_for_shader( particle_shader, 'POINTS', {"pos": particle_vertices, "color": particle_vertex_colors}, @@ -187,6 +193,11 @@ def poll(cls, context): def draw_callback_3d(self, context): + if render.is_rendering(): + # This method does not need to be run while rendering. Can cause + # crashes on certain systems. + return + global particle_vertices global particle_vertex_colors @@ -195,6 +206,9 @@ def draw_callback_3d(self, context): if domain is None or len(particle_vertices) == 0: return + if not dprops.debug.fluid_particles_visibility: + return + if vcu.get_object_hide_viewport(domain): return diff --git a/src/addon/operators/error_operators.py b/src/addon/operators/error_operators.py index d8cebf60..d1360a3f 100644 --- a/src/addon/operators/error_operators.py +++ b/src/addon/operators/error_operators.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/operators/export_operators.py b/src/addon/operators/export_operators.py index a467747f..879d7924 100644 --- a/src/addon/operators/export_operators.py +++ b/src/addon/operators/export_operators.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -327,7 +327,7 @@ def export_simulation_stats_to_csv(self, stats_data, filepath): if d is not None: csv_rows.append(d) - with open(filepath, 'w', newline='') as csvfile: + with open(filepath, 'w', newline='', encoding='utf-8') as csvfile: dprops = bpy.context.scene.flip_fluid.get_domain_properties() if dprops.stats.csv_region_format == 'CSV_REGION_US': delimiter = ',' @@ -351,7 +351,7 @@ def execute(self, context): self.report({"ERROR"}, "Missing simulation stats data file: " + statsfile) return {'CANCELLED'} - with open(statsfile, 'r') as f: + with open(statsfile, 'r', encoding='utf-8') as f: statsdata = json.loads(f.read()) csv_filepath = dprops.stats.csv_save_filepath diff --git a/src/addon/operators/helper_operators.py b/src/addon/operators/helper_operators.py index 907a3911..9f436840 100644 --- a/src/addon/operators/helper_operators.py +++ b/src/addon/operators/helper_operators.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import bpy, os, subprocess, platform, mathutils +import bpy, os, subprocess, platform, mathutils, fnmatch from bpy.props import ( BoolProperty, StringProperty @@ -879,7 +879,7 @@ def execute(self, context): class FlipFluidHelperSetObjectViewportDisplay(bpy.types.Operator): bl_idname = "flip_fluid_operators.helper_set_object_viewport_display" bl_label = "Object Viewport Display" - bl_description = "Set how selected objects are displayed in the viewport" + bl_description = "Set how selected objects are displayed/rendered in the viewport" display_mode = StringProperty("TYPE_NONE") exec(vcu.convert_attribute_to_28("display_mode")) @@ -901,6 +901,7 @@ def execute(self, context): vcu.set_object_display_type(obj, 'TEXTURED') obj.show_wire = False obj.show_all_edges = False + elif self.display_mode == 'DISPLAY_MODE_WIREFRAME': vcu.set_object_display_type(obj, 'WIRE') obj.show_wire = True @@ -909,6 +910,27 @@ def execute(self, context): return {'FINISHED'} +class FlipFluidHelperSetObjectRenderDisplay(bpy.types.Operator): + bl_idname = "flip_fluid_operators.helper_set_object_render_display" + bl_label = "Object Render Display" + bl_description = "Set selected objects visiblility in the render" + + hide_render = BoolProperty(False) + exec(vcu.convert_attribute_to_28("hide_render")) + + + @classmethod + def poll(cls, context): + return bool(context.selected_objects) + + + def execute(self, context): + for obj in context.selected_objects: + obj.hide_render = self.hide_render + + return {'FINISHED'} + + class FlipFluidHelperLoadLastFrame(bpy.types.Operator): bl_idname = "flip_fluid_operators.helper_load_last_frame" bl_label = "Load Last Frame" @@ -1121,6 +1143,7 @@ def execute(self, context): return {'FINISHED'} + class FlipFluidHelperCommandLineRenderToClipboard(bpy.types.Operator): bl_idname = "flip_fluid_operators.helper_command_line_render_to_clipboard" bl_label = "Launch Render" @@ -1130,13 +1153,15 @@ class FlipFluidHelperCommandLineRenderToClipboard(bpy.types.Operator): @classmethod def poll(cls, context): - return bool(bpy.data.filepath) + system = platform.system() + return bool(bpy.data.filepath) and system == "Windows" def execute(self, context): + command_text = "\"" + bpy.app.binary_path + "\" --background \"" + bpy.data.filepath + "\" -a" bpy.context.window_manager.clipboard = command_text - + info_msg = "Copied the following render command to your clipboard:\n\n" info_msg += command_text + "\n\n" info_msg += "For more information on command line rendering, visit our documentation:\n" @@ -1146,6 +1171,145 @@ def execute(self, context): return {'FINISHED'} + +class FlipFluidHelperCommandLineRenderToScriptfile(bpy.types.Operator): + bl_idname = "flip_fluid_operators.helper_cmd_render_to_scriptfile" + bl_label = "Generate Batch File" + bl_description = ("Generates a Windows batch file to render all frames one-by-one." + + " The .blend file will need to be saved before using this operator") + + + @classmethod + def poll(cls, context): + system = platform.system() + return bool(bpy.data.filepath) and system == "Windows" + + + def execute(self, context): + + output_message = "No batch file generated! All frames have been rendered." + output_message_2 = "Click the folder-icon to see the rendered files." + render_directory = os.path.dirname(bpy.data.scenes[0].render.filepath) + + render_absolutedirectory = bpy.path.abspath(render_directory) + render_filename = bpy.context.scene.render.filepath + + frame_start = bpy.context.scene.frame_start + frame_end = bpy.context.scene.frame_end + frames_total = (frame_end +1) - frame_start + + rendered_files_format = bpy.context.scene.render.image_settings.file_format + + rendered_files_format_fixed = rendered_files_format + + + if os.path.exists(render_directory) == False: + os.makedirs(render_directory) + output_message_2 = "Created the directory " + render_absolutedirectory + + if rendered_files_format == "JPEG": + rendered_files_format_fixed = "JPG" + + file_text_contents = "" + file_text_contents += "echo.\n" + + counter_rendered_files = len(fnmatch.filter(os.listdir(render_absolutedirectory),"*." + rendered_files_format_fixed.casefold())) + + if counter_rendered_files != frames_total: + output_message = "A batch file has been generated here: " + output_message_2 = "Rendered files can be found here: " + render_absolutedirectory + formatted_blender_exe_path = "\"" + bpy.app.binary_path + "\"" + formatted_blendfile_path = "\"" + bpy.data.filepath + "\"" + for comparison in range(frames_total): + frame_value = frame_start + comparison + frame_value_string = str(frame_value) + frame_amount = "{:04d}".format(frame_value) + setpoint_filename = render_filename + frame_amount + "." + rendered_files_format_fixed + + if not os.path.exists(setpoint_filename): + command_text = formatted_blender_exe_path + " --background " + formatted_blendfile_path + " -s " + frame_value_string + " -e " + frame_value_string + " -a" + file_text_contents += command_text + "\n" + + directory = os.path.dirname(bpy.data.filepath) + filename = bpy.path.basename(bpy.context.blend_data.filepath) + renderscript_filepath = os.path.join(directory, "RENDER_" + filename + ".bat") + with open(renderscript_filepath, "w") as renderscript_file: + renderscript_file.write(file_text_contents + "\n") + + info_msg = output_message_2 + "\n" + info_msg += output_message + "\n\n" + info_msg += renderscript_filepath + "\n\n" + info_msg += "For more information on batch rendering, visit our documentation:\n" + info_msg += "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Helper-Menu-Settings#command-line-tools" + self.report({'INFO'}, info_msg) + + print(str(counter_rendered_files) + " frames in the " + rendered_files_format_fixed.casefold() + " format has been rendered!") + print(str(max(frames_total - counter_rendered_files, 0)) + " frames are missing!") + + return {'FINISHED'} + + +class FlipFluidHelperRunScriptfile(bpy.types.Operator): + bl_idname = "flip_fluid_operators.helper_run_scriptfile" + bl_label = "Launch Batch File Render" + bl_description = ("Runs the generated batch file. If no batch file has been generated, one will be created automatically." + + " The .blend file will need to be saved before using this operator") + + + @classmethod + def poll(cls, context): + return bool(bpy.data.filepath) + + + def execute(self, context): + directory = os.path.dirname(bpy.data.filepath) + blend_filename = bpy.path.basename(bpy.context.blend_data.filepath) + script_filename = "RENDER_" + blend_filename + ".bat" + batch_filepath = os.path.join(directory, script_filename) + + if not os.path.isfile(batch_filepath): + bpy.ops.flip_fluid_operators.helper_cmd_render_to_scriptfile() + if not os.path.isfile(batch_filepath): + self.report({'ERROR'}, "Unable to generate the render script.") + + os.startfile(batch_filepath) + + info_msg = "Running now the renderscript!\n\n" + info_msg += "For more information on batchfile rendering, visit our documentation:\n" + info_msg += "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Helper-Menu-Settings#command-line-tools" + self.report({'INFO'}, info_msg) + return {'FINISHED'} + +class FlipFluidHelperOpenOutputFolder(bpy.types.Operator): + bl_idname = "flip_fluid_operators.helper_open_outputfolder" + bl_label = "Opens The Output Folder" + bl_description = ("Opens the output-folder that is set in the output settings. If the folder does not exist, it will be created." + + " The .blend file will need to be saved before using this operator") + + + @classmethod + def poll(cls, context): + return bool(bpy.data.filepath) + + + def execute(self, context): + + render_directory = os.path.dirname(bpy.data.scenes[0].render.filepath) + render_absolutedirectory = bpy.path.abspath(render_directory) + + output_message_2 = "Opening the directory " + render_absolutedirectory + if os.path.exists(render_absolutedirectory) == False: + os.makedirs(render_absolutedirectory) + output_message_2 = "Created the directory " + render_absolutedirectory + + os.startfile(os.path.realpath(render_absolutedirectory)) + + info_msg = output_message_2 + + return {'FINISHED'} + + + class FlipFluidHelperStableRendering279(bpy.types.Operator): bl_idname = "flip_fluid_operators.helper_stable_rendering_279" bl_label = "Enable Stable Rendering" @@ -1157,7 +1321,12 @@ class FlipFluidHelperStableRendering279(bpy.types.Operator): @classmethod def poll(cls, context): - return context.scene.render.display_mode != 'SCREEN' + # render.display_mode is only available in Blender 2.79 + # poll() should return false for any other version of Blender + try: + return context.scene.render.display_mode != 'SCREEN' + except: + return False def execute(self, context): @@ -1327,11 +1496,15 @@ def register(): bpy.utils.register_class(FlipFluidHelperUndoOrganizeOutliner) bpy.utils.register_class(FlipFluidHelperUndoSeparateFLIPMeshes) bpy.utils.register_class(FlipFluidHelperSetObjectViewportDisplay) + bpy.utils.register_class(FlipFluidHelperSetObjectRenderDisplay) bpy.utils.register_class(FlipFluidHelperLoadLastFrame) bpy.utils.register_class(FlipFluidHelperCommandLineBake) bpy.utils.register_class(FlipFluidHelperCommandLineBakeToClipboard) bpy.utils.register_class(FlipFluidHelperCommandLineRender) bpy.utils.register_class(FlipFluidHelperCommandLineRenderToClipboard) + bpy.utils.register_class(FlipFluidHelperCommandLineRenderToScriptfile) + bpy.utils.register_class(FlipFluidHelperRunScriptfile) + bpy.utils.register_class(FlipFluidHelperOpenOutputFolder) bpy.utils.register_class(FlipFluidHelperStableRendering279) bpy.utils.register_class(FlipFluidHelperStableRendering28) bpy.utils.register_class(FlipFluidHelperSetLinearOverrideKeyframes) @@ -1360,11 +1533,15 @@ def unregister(): bpy.utils.unregister_class(FlipFluidHelperUndoOrganizeOutliner) bpy.utils.unregister_class(FlipFluidHelperUndoSeparateFLIPMeshes) bpy.utils.unregister_class(FlipFluidHelperSetObjectViewportDisplay) + bpy.utils.unregister_class(FlipFluidHelperSetObjectRenderDisplay) bpy.utils.unregister_class(FlipFluidHelperLoadLastFrame) bpy.utils.unregister_class(FlipFluidHelperCommandLineBake) bpy.utils.unregister_class(FlipFluidHelperCommandLineBakeToClipboard) bpy.utils.unregister_class(FlipFluidHelperCommandLineRender) bpy.utils.unregister_class(FlipFluidHelperCommandLineRenderToClipboard) + bpy.utils.unregister_class(FlipFluidHelperCommandLineRenderToScriptfile) + bpy.utils.unregister_class(FlipFluidHelperRunScriptfile) + bpy.utils.unregister_class(FlipFluidHelperOpenOutputFolder) bpy.utils.unregister_class(FlipFluidHelperStableRendering279) bpy.utils.unregister_class(FlipFluidHelperStableRendering28) bpy.utils.unregister_class(FlipFluidHelperSetLinearOverrideKeyframes) diff --git a/src/addon/operators/material_operators.py b/src/addon/operators/material_operators.py index 8de5e004..31155cc4 100644 --- a/src/addon/operators/material_operators.py +++ b/src/addon/operators/material_operators.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/operators/object_operators.py b/src/addon/operators/object_operators.py index 6ffbc402..b9311697 100644 --- a/src/addon/operators/object_operators.py +++ b/src/addon/operators/object_operators.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/operators/preferences_operators.py b/src/addon/operators/preferences_operators.py index a834e5b2..97fcb15d 100644 --- a/src/addon/operators/preferences_operators.py +++ b/src/addon/operators/preferences_operators.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -102,7 +102,7 @@ def create_archive(self): user_info_str = json.dumps(user_info, sort_keys=True, indent=4) user_info_filepath = os.path.join(temp_dir, "user_settings.info") - with open(user_info_filepath, 'w') as f: + with open(user_info_filepath, 'w', encoding='utf-8') as f: f.write(user_info_str) addon_path = _get_addon_directory() diff --git a/src/addon/operators/preset_operators.py b/src/addon/operators/preset_operators.py index ceadbf5b..70feb282 100644 --- a/src/addon/operators/preset_operators.py +++ b/src/addon/operators/preset_operators.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/operators/render_operators.py b/src/addon/operators/render_operators.py index 35a197b7..4336c3a2 100644 --- a/src/addon/operators/render_operators.py +++ b/src/addon/operators/render_operators.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/operators/world_operators.py b/src/addon/operators/world_operators.py index 383e9f81..7dbbe878 100644 --- a/src/addon/operators/world_operators.py +++ b/src/addon/operators/world_operators.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/presets/__init__.py b/src/addon/presets/__init__.py index 9d68e069..5b094bee 100644 --- a/src/addon/presets/__init__.py +++ b/src/addon/presets/__init__.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/presets/preset_library.py b/src/addon/presets/preset_library.py index 5c63954a..1f132480 100644 --- a/src/addon/presets/preset_library.py +++ b/src/addon/presets/preset_library.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -268,7 +268,7 @@ def destroy_dummy_domain_object(domain_object): def get_system_default_preset_dict(): sys_path = __get_sys_preset_path() default_preset_path = os.path.join(sys_path, "default.preset") - with open(default_preset_path, 'r') as f: + with open(default_preset_path, 'r', encoding='utf-8') as f: try: data = json.loads(f.read()) except: @@ -319,7 +319,7 @@ def load_default_settings(domain_properties): if not os.path.isfile(default_preset_file): return - with open(default_preset_file, 'r') as f: + with open(default_preset_file, 'r', encoding='utf-8') as f: try: default_data = json.loads(f.read()) except: @@ -336,7 +336,7 @@ def restore_default_settings(domain_properties): if not os.path.isfile(default_preset_file): return "Missing default preset file: <" + default_preset_file + ">" - with open(default_preset_file, 'r') as f: + with open(default_preset_file, 'r', encoding='utf-8') as f: try: default_data = json.loads(f.read()) except: @@ -525,7 +525,7 @@ def decode_package_zipfile(filepath, dst_data): if package_file is None: return "Unable to find package info file" - with zfile.open(package_file, "r") as info_file: + with zfile.open(package_file, "r", encoding='utf-8') as info_file: try: pinfo = json.loads(info_file.read().decode("utf-8")) except: @@ -539,7 +539,7 @@ def decode_package_zipfile(filepath, dst_data): dst_data.update(pinfo) dst_data['presets'] = [] for f in preset_data_files: - with zfile.open(f, "r") as info_file: + with zfile.open(f, 'r', encoding='utf-8') as info_file: try: info = json.loads(info_file.read().decode("utf-8")) except: @@ -623,7 +623,7 @@ def __create_empty_blend_file(dst_path): def __write_dict_to_json(d, filepath): jsonstr = json.dumps(d, sort_keys=True, indent=4) - with open(filepath, 'w') as f: + with open(filepath, 'w', encoding='utf-8') as f: f.write(jsonstr) @@ -801,7 +801,7 @@ def __get_package_info_list_from_path(path): if os.path.isdir(dirpath): info_filepath = os.path.join(dirpath, "package.info") if os.path.isfile(info_filepath): - with open(info_filepath, 'r') as f: + with open(info_filepath, 'r', encoding='utf-8') as f: try: package_info = json.loads(f.read()) package_info["path"] = dirpath @@ -830,7 +830,7 @@ def __get_preset_info_list_from_path(path): if not os.path.isfile(package_info_filepath): continue - with open(package_info_filepath, 'r') as f: + with open(package_info_filepath, 'r', encoding='utf-8') as f: try: package_info = json.loads(f.read()) except: @@ -848,7 +848,7 @@ def __get_preset_info_list_from_path(path): if not os.path.isfile(preset_info_filepath): continue - with open(preset_info_filepath, 'r') as f: + with open(preset_info_filepath, 'r', encoding='utf-8') as f: try: preset_info = json.loads(f.read()) except: diff --git a/src/addon/properties/__init__.py b/src/addon/properties/__init__.py index 1267be6d..f43769ae 100644 --- a/src/addon/properties/__init__.py +++ b/src/addon/properties/__init__.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/properties/custom_properties.py b/src/addon/properties/custom_properties.py index bdc405a1..edac32d8 100644 --- a/src/addon/properties/custom_properties.py +++ b/src/addon/properties/custom_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/properties/domain_advanced_properties.py b/src/addon/properties/domain_advanced_properties.py index 3989af3c..28544730 100644 --- a/src/addon/properties/domain_advanced_properties.py +++ b/src/addon/properties/domain_advanced_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -76,6 +76,13 @@ class DomainAdvancedProperties(bpy.types.PropertyGroup): " initial fluid shape", default=False, ); exec(conv("jitter_surface_particles")) + velocity_transfer_method = EnumProperty( + name="Velocity Transfer Method", + description="Simulation method to use", + items=types.velocity_transfer_methods, + default='VELOCITY_TRANSFER_METHOD_FLIP', + options={'HIDDEN'}, + ); exec(conv("velocity_transfer_method")) PICFLIP_ratio = FloatProperty( name="PIC/FLIP Ratio", description="Ratio of PIC velocity to FLIP velocity update mixture." @@ -88,6 +95,14 @@ class DomainAdvancedProperties(bpy.types.PropertyGroup): precision=2, subtype='FACTOR', ); exec(conv("PICFLIP_ratio")) + PICAPIC_ratio = FloatProperty( + name="PIC/APIC Ratio", + description="Placeholder", + min=0.0, max=1.0, + default=0.00, + precision=2, + subtype='FACTOR', + ); exec(conv("PICAPIC_ratio")) CFL_condition_number = IntProperty( name="Safety Factor (CFL Number)", description="Maximum number of grid cells a particle can travel" @@ -167,6 +182,15 @@ class DomainAdvancedProperties(bpy.types.PropertyGroup): options={'HIDDEN'}, ); exec(conv("disable_changing_topology_warning")) + surface_tension_substeps_exceeded_tooltip = BoolProperty( + name="Warning: Not Enough Max Substeps", + description="The estimated number of Surface Tension substeps per frame exceeds the Max Frame" + " Substeps value. This can cause an unstable simulation. Either decrease the amount of" + " Surface Tension in the FLIP Fluid World panel to lower the number of required substeps or" + " increase the number of allowed Max Frame Substeps in the FLIP Fluid Advanced panel", + default=True, + ); exec(conv("surface_tension_substeps_exceeded_tooltip")) + def register_preset_properties(self, registry, path): add = registry.add_property @@ -175,7 +199,9 @@ def register_preset_properties(self, registry, path): add(path + ".enable_adaptive_force_field_time_stepping", "Adaptive Force Field Stepping", group_id=0) add(path + ".particle_jitter_factor", "Jitter Factor", group_id=0) add(path + ".jitter_surface_particles", "Jitter Surface Particles", group_id=0) + add(path + ".velocity_transfer_method", "Velocity Transfer Method", group_id=0) add(path + ".PICFLIP_ratio", "PIC/FLIP Ratio", group_id=0) + add(path + ".PICAPIC_ratio", "PIC/APIC Ratio", group_id=0) add(path + ".CFL_condition_number", "CFL", group_id=0) add(path + ".enable_extreme_velocity_removal", "Enable Extreme Velocity Removal", group_id=0) add(path + ".enable_gpu_features", "Enable GPU Features", group_id=1) diff --git a/src/addon/properties/domain_bake_properties.py b/src/addon/properties/domain_bake_properties.py index 4831fa42..5e1f9866 100644 --- a/src/addon/properties/domain_bake_properties.py +++ b/src/addon/properties/domain_bake_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -92,14 +92,14 @@ def check_autosave(self): return try: - with open(autosave_info_file, 'r') as f: + with open(autosave_info_file, 'r', encoding='utf-8') as f: autosave_info = json.loads(f.read()) except: # Autosave file might not be completely written. Wait and try again. import time time.sleep(0.25) try: - with open(autosave_info_file, 'r') as f: + with open(autosave_info_file, 'r', encoding='utf-8') as f: autosave_info = json.loads(f.read()) except: # skip this autosave frame if it still cannot be read. The autosave @@ -144,8 +144,9 @@ def _update_savestate_enums(self): dprops = bpy.context.scene.flip_fluid.get_domain_properties() cache_directory = dprops.cache.get_cache_abspath() savestates_directory = os.path.join(cache_directory, "savestates") - subdirs = os.listdir(savestates_directory) - subdirs.remove("autosave") + subdirs = [d for d in os.listdir(savestates_directory) if os.path.isdir(os.path.join(savestates_directory, d))] + if "autosave" in subdirs: + subdirs.remove("autosave") autosave_frame = self.autosave_frame savestate_frames = [] diff --git a/src/addon/properties/domain_cache_properties.py b/src/addon/properties/domain_cache_properties.py index 1140e46f..ea6b20d0 100644 --- a/src/addon/properties/domain_cache_properties.py +++ b/src/addon/properties/domain_cache_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/properties/domain_debug_properties.py b/src/addon/properties/domain_debug_properties.py index 0281518e..e884c26c 100644 --- a/src/addon/properties/domain_debug_properties.py +++ b/src/addon/properties/domain_debug_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -148,11 +148,17 @@ class DomainDebugProperties(bpy.types.PropertyGroup): export_fluid_particles = BoolProperty( name="Enable Fluid Particle Debugging", description="Enable to export simulator fluid particle data and to" - " visualize and debug problems with fluid behaviour. Enable " + " visualize and debug problems with fluid behaviour. Enable" " this option before baking a simulation to use this feature", default=False, update=lambda self, context: self._update_export_fluid_particles(context), ); exec(conv("export_fluid_particles")) + fluid_particles_visibility = BoolProperty( + name="Fluid Particle Visibility", + description="Show fluid particles in the viewport", + default=True, + update=lambda self, context: self._update_export_fluid_particles(context), + ); exec(conv("fluid_particles_visibility")) low_speed_particle_color = FloatVectorProperty( name="Low Speed Color", subtype='COLOR', @@ -215,6 +221,12 @@ class DomainDebugProperties(bpy.types.PropertyGroup): default=False, update=lambda self, context: self._update_export_force_field(context), ); exec(conv("export_force_field")) + force_field_visibility = BoolProperty( + name="Force Field Visibility", + description="Show force fields in the viewport", + default=True, + update=lambda self, context: self._update_export_force_field(context), + ); exec(conv("force_field_visibility")) low_force_field_color = FloatVectorProperty( name="Low Force Color", subtype='COLOR', @@ -279,6 +291,14 @@ class DomainDebugProperties(bpy.types.PropertyGroup): default=False, update=lambda self, context: self._update_export_internal_obstacle_mesh(context), ); exec(conv("export_internal_obstacle_mesh")) + internal_obstacle_mesh_visibility = BoolProperty( + name="Obstacle Debugging Visibility", + description="Show obstacle debug mesh in the viewport. If disabled, this prevents debug obstacle" + " mesh data from being loaded into Blender. Frame must be reloaded after enabling this option for" + " mesh to reload and become visible", + default=True, + update=lambda self, context: self._update_export_internal_obstacle_mesh(context), + ); exec(conv("internal_obstacle_mesh_visibility")) display_console_output = BoolProperty( name="Display Console Output", @@ -301,31 +321,34 @@ class DomainDebugProperties(bpy.types.PropertyGroup): def register_preset_properties(self, registry, path): add = registry.add_property - add(path + ".display_simulation_grid", "Display Domain Grid", group_id=0) - add(path + ".grid_display_mode", "Grid Display Mode", group_id=0) - add(path + ".grid_display_scale", "Grid Scale", group_id=0) - add(path + ".enabled_debug_grids", "Draw Grids", group_id=0) - add(path + ".x_grid_color", "X Grid Color", group_id=0) - add(path + ".y_grid_color", "Y Grid Color", group_id=0) - add(path + ".z_grid_color", "Z Grid Color", group_id=0) - add(path + ".debug_grid_offsets", "Grid Offsets", group_id=0) - add(path + ".snap_offsets_to_grid", "Snap Offsets to Grid", group_id=0) - add(path + ".export_fluid_particles", "Enable Fluid Particle Debugging", group_id=1) - add(path + ".low_speed_particle_color", "Low Velocity Particle Color", group_id=1) - add(path + ".high_speed_particle_color", "High Velocity Particle Color", group_id=1) - add(path + ".min_gradient_speed", "Low-High Particle Velocities", group_id=1) - add(path + ".max_gradient_speed", "Low-High Particle Velocities", group_id=1) - add(path + ".fluid_particle_gradient_mode", "Fluid Speed Gradient Mode", group_id=1) - add(path + ".particle_size", "Particle Size", group_id=1) - add(path + ".low_force_field_color", "Low Force Field Color", group_id=2) - add(path + ".high_force_field_color", "High Force Field Color", group_id=2) - add(path + ".min_gradient_force", "Low-High Force Strength", group_id=2) - add(path + ".max_gradient_force", "Low-High Force Strength", group_id=2) - add(path + ".force_field_gradient_mode", "Fluid Speed Gradient Mode", group_id=2) - add(path + ".export_force_field", "Enable Force Field Debugging", group_id=2) - add(path + ".force_field_line_size", "Line Size", group_id=2) - add(path + ".export_internal_obstacle_mesh", "Enable Obstacle Debugging", group_id=3) - add(path + ".display_console_output", "Display Console Output", group_id=3) + add(path + ".display_simulation_grid", "Display Domain Grid", group_id=0) + add(path + ".grid_display_mode", "Grid Display Mode", group_id=0) + add(path + ".grid_display_scale", "Grid Scale", group_id=0) + add(path + ".enabled_debug_grids", "Draw Grids", group_id=0) + add(path + ".x_grid_color", "X Grid Color", group_id=0) + add(path + ".y_grid_color", "Y Grid Color", group_id=0) + add(path + ".z_grid_color", "Z Grid Color", group_id=0) + add(path + ".debug_grid_offsets", "Grid Offsets", group_id=0) + add(path + ".snap_offsets_to_grid", "Snap Offsets to Grid", group_id=0) + add(path + ".export_fluid_particles", "Enable Fluid Particle Debugging", group_id=1) + add(path + ".fluid_particles_visibility", "Fluid Particle Visibility", group_id=1) + add(path + ".low_speed_particle_color", "Low Velocity Particle Color", group_id=1) + add(path + ".high_speed_particle_color", "High Velocity Particle Color", group_id=1) + add(path + ".min_gradient_speed", "Low-High Particle Velocities", group_id=1) + add(path + ".max_gradient_speed", "Low-High Particle Velocities", group_id=1) + add(path + ".fluid_particle_gradient_mode", "Fluid Speed Gradient Mode", group_id=1) + add(path + ".particle_size", "Particle Size", group_id=1) + add(path + ".low_force_field_color", "Low Force Field Color", group_id=2) + add(path + ".high_force_field_color", "High Force Field Color", group_id=2) + add(path + ".min_gradient_force", "Low-High Force Strength", group_id=2) + add(path + ".max_gradient_force", "Low-High Force Strength", group_id=2) + add(path + ".force_field_gradient_mode", "Fluid Speed Gradient Mode", group_id=2) + add(path + ".export_force_field", "Enable Force Field Debugging", group_id=2) + add(path + ".force_field_visibility", "Force Field Visibility", group_id=2) + add(path + ".force_field_line_size", "Line Size", group_id=2) + add(path + ".export_internal_obstacle_mesh", "Enable Obstacle Debugging", group_id=3) + add(path + ".internal_obstacle_mesh_visibility", "Obstacle Debugging Visibility", group_id=3) + add(path + ".display_console_output", "Display Console Output", group_id=3) def load_post(self): @@ -401,9 +424,11 @@ def _update_export_internal_obstacle_mesh(self, context): if dprops is None: return - if self.export_internal_obstacle_mesh: + if self.export_internal_obstacle_mesh and self.internal_obstacle_mesh_visibility: dprops.mesh_cache.initialize_cache_objects() - else: + elif self.export_internal_obstacle_mesh and not self.internal_obstacle_mesh_visibility: + dprops.mesh_cache.obstacle.reset_cache_object() + else: dprops.mesh_cache.delete_obstacle_cache_object() diff --git a/src/addon/properties/domain_materials_properties.py b/src/addon/properties/domain_materials_properties.py index b97838cf..618552f4 100644 --- a/src/addon/properties/domain_materials_properties.py +++ b/src/addon/properties/domain_materials_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/properties/domain_presets_properties.py b/src/addon/properties/domain_presets_properties.py index f90ddd65..c0fa20ca 100644 --- a/src/addon/properties/domain_presets_properties.py +++ b/src/addon/properties/domain_presets_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/properties/domain_properties.py b/src/addon/properties/domain_properties.py index 99356c8d..63c8f150 100644 --- a/src/addon/properties/domain_properties.py +++ b/src/addon/properties/domain_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/properties/domain_render_properties.py b/src/addon/properties/domain_render_properties.py index be23e673..938861f6 100644 --- a/src/addon/properties/domain_render_properties.py +++ b/src/addon/properties/domain_render_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/properties/domain_simulation_properties.py b/src/addon/properties/domain_simulation_properties.py index c39aebf6..1d2063cb 100644 --- a/src/addon/properties/domain_simulation_properties.py +++ b/src/addon/properties/domain_simulation_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -205,25 +205,37 @@ class DomainSimulationProperties(bpy.types.PropertyGroup): grid_voxels_tooltip = BoolProperty( name="Grid Voxels Tooltip", - description="The domain is a 3D grid of cubes called voxels, or cells. This info shows the number of voxels on each of the X/Y/Z axis of the domain. The voxels in the 3D grid are similar to the 2D pixels in a 2D image. Instead of storing color data, the voxels store physics data", + description="The domain is a 3D grid of cubes called voxels, or cells. This info shows the" + " number of voxels on each of the X/Y/Z axis of the domain. The voxels in the 3D grid are" + " similar to the 2D pixels in a 2D image, except instead of storing color data, the voxels store" + " physics data", default=True, ); exec(conv("grid_voxels_tooltip")) grid_dimensions_tooltip = BoolProperty( name="Grid Dimensions Tooltip", - description="Displays the physical scale of the domain on the X/Y/Z axis in meters. Setting an appropriate scale can be an important factor for realistic motion and speed of your simulated fluid", + description="Displays the physical scale of the domain on the X/Y/Z axis in meters." + " Setting an appropriate scale can be an important factor for realistic motion and speed" + " of your simulated fluid", default=True, ); exec(conv("grid_dimensions_tooltip")) grid_voxel_size_tooltip = BoolProperty( name="Voxel Size Tooltip", - description="Displays the physical size of a single voxel. You can think of a voxel as being the 3D version of a 2D image pixel. In an image, the pixel size is the minimum amount of detail that can be resolved in the picture. In the domain, the voxel size is the minimum amount of physics detail that can be resolved in the simulation such as the smallest droplets and ripples or the thinnest splashes", + description="Displays the physical size of a single voxel. You can think of a voxel as" + " the 3D version of a 2D image pixel. In an image, the pixel size is the minimum" + " amount of detail that can be resolved in the picture. In the domain, the voxel size is" + " the minimum amount of physics detail that can be resolved in the simulation such as the" + " smallest droplets and ripples or the thinnest splashes", default=True, ); exec(conv("grid_voxel_size_tooltip")) grid_voxel_count_tooltip = BoolProperty( name="Voxel Count Tooltip", - description="Displays the total number of voxels in the domain. Physics are computed each voxel and the total count can be a measure for how much work your system will be doing. Small simulation = around 2 million. Medium = around 10M. Large = around 40M. Very Large = over 80M", + description="Displays the total number of voxels in the domain. Physics are computed for each" + " voxel and the total count can be a measure for how much work your system will be doing." + " Small simulation = around 2 Million. Medium = around 10M. Large = around 40M." + " Very Large = over 80M", default=True, ); exec(conv("grid_voxel_count_tooltip")) @@ -532,7 +544,7 @@ def _update_selected_savestate_grid_dimensions(self, context): if not os.path.isfile(autosave_info_file): return - with open(autosave_info_file, 'r') as f: + with open(autosave_info_file, 'r', encoding='utf-8') as f: autosave_info = json.loads(f.read()) try: diff --git a/src/addon/properties/domain_stats_properties.py b/src/addon/properties/domain_stats_properties.py index 1605c559..b6353618 100644 --- a/src/addon/properties/domain_stats_properties.py +++ b/src/addon/properties/domain_stats_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -266,6 +266,9 @@ def refresh_stats(self): self._update_frame_stats() elif self.cache_info_type == "CACHE_INFO": self._update_cache_stats() + + self._update_estimated_time_remaining() + self.is_stats_current = True @@ -303,6 +306,8 @@ def _update_cache_info_type(self, context): self.current_info_frame = context.scene.frame_current self._update_frame_stats() + self._update_estimated_time_remaining() + def _update_lock_info_frame_to_timeline(self, context): if self.lock_info_frame_to_timeline: @@ -321,7 +326,7 @@ def _update_frame_stats(self): self.is_frame_info_available = False return - with open(statsfile, 'r') as f: + with open(statsfile, 'r', encoding='utf-8') as f: statsdata = json.loads(f.read()) framekey = str(self.current_info_frame) @@ -463,7 +468,7 @@ def _update_cache_stats(self): self.is_frame_info_available = False return - with open(statsfile, 'r') as f: + with open(statsfile, 'r', encoding='utf-8') as f: cachedata = json.loads(f.read()) self.is_cache_info_available = True @@ -625,18 +630,6 @@ def _update_cache_stats(self): self.time_objects.set_time_pct( 100 * time_objects / total_time) self.time_other.set_time_pct( 100 * time_other / total_time) - frame_speed = self._get_estimated_frame_speed(cachedata) - self.estimated_frame_speed = frame_speed - self.is_estimated_time_remaining_available = frame_speed > 0 - - if self.is_estimated_time_remaining_available: - num_frames = dprops.simulation.frame_end - dprops.simulation.frame_start + 1 - frames_left = num_frames - dprops.bake.num_baked_frames - time_remaining = int(math.ceil((1.0 / frame_speed) * frames_left)) - time_remaining = min(time_remaining, 2147483648 - 1) - self.estimated_time_remaining = time_remaining - self.estimated_time_remaining_timestamp = self.get_timestamp() - self._update_cache_size(cachedata) @@ -682,6 +675,33 @@ def _get_estimated_frame_speed(self, cachedata): return average_speed + def _update_estimated_time_remaining(self): + dprops = bpy.context.scene.flip_fluid.get_domain_properties() + if dprops is None: + return + + cache_directory = dprops.cache.get_cache_abspath() + statsfile = os.path.join(cache_directory, self.stats_filename) + if not os.path.isfile(statsfile): + return + + with open(statsfile, 'r', encoding='utf-8') as f: + cachedata = json.loads(f.read()) + + frame_speed = self._get_estimated_frame_speed(cachedata) + self.estimated_frame_speed = frame_speed + self.is_estimated_time_remaining_available = frame_speed > 0 + + if self.is_estimated_time_remaining_available: + num_frames = dprops.simulation.frame_end - dprops.simulation.frame_start + 1 + frames_left = num_frames - dprops.bake.num_baked_frames + time_remaining = int(math.ceil((1.0 / frame_speed) * frames_left)) + time_remaining = min(time_remaining, 2147483648 - 1) + self.estimated_time_remaining = time_remaining + self.estimated_time_remaining_timestamp = self.get_timestamp() + + + def register(): bpy.utils.register_class(ByteProperty) bpy.utils.register_class(MeshStatsProperties) diff --git a/src/addon/properties/domain_surface_properties.py b/src/addon/properties/domain_surface_properties.py index 7db89a28..87c1aa6c 100644 --- a/src/addon/properties/domain_surface_properties.py +++ b/src/addon/properties/domain_surface_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/properties/domain_whitewater_properties.py b/src/addon/properties/domain_whitewater_properties.py index 7f3c14c6..a2ae6f12 100644 --- a/src/addon/properties/domain_whitewater_properties.py +++ b/src/addon/properties/domain_whitewater_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/properties/domain_world_properties.py b/src/addon/properties/domain_world_properties.py index 6116f141..8beb928d 100644 --- a/src/addon/properties/domain_world_properties.py +++ b/src/addon/properties/domain_world_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -112,6 +112,14 @@ class DomainWorldProperties(bpy.types.PropertyGroup): update=lambda self, context: self._update_viscosity_exponent(context), options={'HIDDEN'}, ); exec(conv("viscosity_exponent")) + viscosity_solver_error_tolerance = IntProperty( + description="Accuracy of the viscosity solver. Decrease to speed up baking at the cost of accuracy," + " increase to improve accuracy at the cost of baking speed. High viscosity thick or stiff fluids" + " benefit the most from increasing accuracy. Low viscosity thin fluids often work well at the lowest" + " accuracy. Setting above a value of 4 may have greatly diminishing returns on improvement", + min=1, max=6, + default=4, + ); exec(conv("viscosity_solver_error_tolerance")) enable_surface_tension = BoolProperty( name="Enable Surface Tension", description="Enable surface tension forces", @@ -202,6 +210,15 @@ class DomainWorldProperties(bpy.types.PropertyGroup): default=True, ); exec(conv("surface_tension_substeps_tooltip")) + surface_tension_substeps_exceeded_tooltip = BoolProperty( + name="Warning: Too Many Substeps", + description="The estimated number of Surface Tension substeps per frame exceeds the Max Frame" + " Substeps value. This can cause an unstable simulation. Either decrease the amount of" + " Surface Tension in the FLIP Fluid World panel to lower the number of required substeps or" + " increase the number of allowed Max Frame Substeps in the FLIP Fluid Advanced panel", + default=True, + ); exec(conv("surface_tension_substeps_exceeded_tooltip")) + minimum_surface_tension_cfl = FloatProperty(default=0.25) exec(conv("minimum_surface_tension_cfl")) @@ -227,26 +244,26 @@ def frame_change_post(self, scene): # Accounts for keyframed value changes after a frame change self._update_surface_tension_info() - def register_preset_properties(self, registry, path): add = registry.add_property - add(path + ".world_scale_mode", "World Scaling Mode", group_id=0) - add(path + ".world_scale_relative", "Relative Scale", group_id=0) - add(path + ".world_scale_absolute", "Absolute Scale", group_id=0) - add(path + ".gravity_type", "Gravity Type", group_id=0) - add(path + ".gravity", "Gravity", group_id=0) - add(path + ".force_field_resolution", "Force Field Resolution", group_id=0) - add(path + ".enable_viscosity", "Enable Viscosity", group_id=0) - add(path + ".viscosity", "Viscosity Base", group_id=0) - add(path + ".viscosity_exponent", "Viscosity Exponent", group_id=0) - add(path + ".enable_surface_tension", "Enable Surface Tension", group_id=0) - add(path + ".surface_tension", "Surface Tension", group_id=0) - add(path + ".surface_tension_exponent", "Surface Tension Exponent", group_id=0) - add(path + ".surface_tension_accuracy", "Surface Tension Accuracy", group_id=0) - add(path + ".enable_sheet_seeding", "Enable Sheeting Effects", group_id=0) - add(path + ".sheet_fill_rate", "Sheeting Strength", group_id=0) - add(path + ".sheet_fill_threshold", "Sheeting Thickness", group_id=0) - add(path + ".boundary_friction", "Boundary Friction", group_id=0) + add(path + ".world_scale_mode", "World Scaling Mode", group_id=0) + add(path + ".world_scale_relative", "Relative Scale", group_id=0) + add(path + ".world_scale_absolute", "Absolute Scale", group_id=0) + add(path + ".gravity_type", "Gravity Type", group_id=0) + add(path + ".gravity", "Gravity", group_id=0) + add(path + ".force_field_resolution", "Force Field Resolution", group_id=0) + add(path + ".enable_viscosity", "Enable Viscosity", group_id=0) + add(path + ".viscosity", "Viscosity Base", group_id=0) + add(path + ".viscosity_exponent", "Viscosity Exponent", group_id=0) + add(path + ".viscosity_solver_error_tolerance", "Viscosity Accuracy", group_id=0) + add(path + ".enable_surface_tension", "Enable Surface Tension", group_id=0) + add(path + ".surface_tension", "Surface Tension", group_id=0) + add(path + ".surface_tension_exponent", "Surface Tension Exponent", group_id=0) + add(path + ".surface_tension_accuracy", "Surface Tension Accuracy", group_id=0) + add(path + ".enable_sheet_seeding", "Enable Sheeting Effects", group_id=0) + add(path + ".sheet_fill_rate", "Sheeting Strength", group_id=0) + add(path + ".sheet_fill_threshold", "Sheeting Thickness", group_id=0) + add(path + ".boundary_friction", "Boundary Friction", group_id=0) def get_gravity_data_dict(self): diff --git a/src/addon/properties/flip_fluid_properties.py b/src/addon/properties/flip_fluid_properties.py index 6a2986fd..d9e4105a 100644 --- a/src/addon/properties/flip_fluid_properties.py +++ b/src/addon/properties/flip_fluid_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/properties/fluid_properties.py b/src/addon/properties/fluid_properties.py index fb2da736..8fb8b95e 100644 --- a/src/addon/properties/fluid_properties.py +++ b/src/addon/properties/fluid_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/properties/force_field_properties.py b/src/addon/properties/force_field_properties.py index f907f08c..9e97c2a7 100644 --- a/src/addon/properties/force_field_properties.py +++ b/src/addon/properties/force_field_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/properties/helper_properties.py b/src/addon/properties/helper_properties.py index 8ec3b22d..695caef3 100644 --- a/src/addon/properties/helper_properties.py +++ b/src/addon/properties/helper_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/properties/inflow_properties.py b/src/addon/properties/inflow_properties.py index c1bdd9b3..4474b752 100644 --- a/src/addon/properties/inflow_properties.py +++ b/src/addon/properties/inflow_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/properties/material_properties.py b/src/addon/properties/material_properties.py index 54915455..9eb989e3 100644 --- a/src/addon/properties/material_properties.py +++ b/src/addon/properties/material_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/properties/object_properties.py b/src/addon/properties/object_properties.py index caec8a7a..369d46b9 100644 --- a/src/addon/properties/object_properties.py +++ b/src/addon/properties/object_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -50,6 +50,7 @@ ) from .. import types from ..utils import version_compatibility_utils as vcu +from ..utils import api_workaround_utils class ObjectViewSettings(bpy.types.PropertyGroup): @@ -137,8 +138,7 @@ def scene_update_post(self, scene, bl_object): # not updated to reflect the above 'hide_render' change. Toggling # the hide_viewport option on and off is a workaround to get the viewport # to update. - vcu.toggle_outline_eye_icon(bl_object) - vcu.toggle_outline_eye_icon(bl_object) + api_workaround_utils.toggle_viewport_visibility_to_update_rendered_viewport_workaround(bl_object) def get_object_type(): diff --git a/src/addon/properties/obstacle_properties.py b/src/addon/properties/obstacle_properties.py index ff46455b..c3a8f813 100644 --- a/src/addon/properties/obstacle_properties.py +++ b/src/addon/properties/obstacle_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/properties/outflow_properties.py b/src/addon/properties/outflow_properties.py index 2d32bbeb..cc1996ef 100644 --- a/src/addon/properties/outflow_properties.py +++ b/src/addon/properties/outflow_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/properties/preferences_properties.py b/src/addon/properties/preferences_properties.py index 92fe48d8..6e37c528 100644 --- a/src/addon/properties/preferences_properties.py +++ b/src/addon/properties/preferences_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -116,6 +116,13 @@ class FLIPFluidAddonPreferences(bpy.types.AddonPreferences): ); exec(vcu.convert_attribute_to_28("engine_debug_mode")) + enable_developer_tools = BoolProperty( + name="Enable Developer Tools", + description="Enable Developer Tools", + default=False, + ); + exec(vcu.convert_attribute_to_28("enable_developer_tools")) + enable_presets = BoolProperty( name="Enable Presets", description="Presets are a deprecated feature that will no longer be updated. Enable to use the older preset" @@ -203,6 +210,7 @@ def draw(self, context): row.enabled = self.enable_helper row.prop(self, "helper_category_name") helper_column.prop(self, "engine_debug_mode") + helper_column.prop(self, "enable_developer_tools") helper_column.separator() helper_column.separator() diff --git a/src/addon/properties/preset_properties.py b/src/addon/properties/preset_properties.py index 3618fe8d..3117e7b7 100644 --- a/src/addon/properties/preset_properties.py +++ b/src/addon/properties/preset_properties.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/render.py b/src/addon/render.py index 028b3303..9aeaf93e 100644 --- a/src/addon/render.py +++ b/src/addon/render.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -485,7 +485,7 @@ def __load_obstacle_debug_frame(frameno, force_reload=False): return dprops = __get_domain_properties() - if not dprops.debug.export_internal_obstacle_mesh: + if not dprops.debug.export_internal_obstacle_mesh or not dprops.debug.internal_obstacle_mesh_visibility: return force_load = force_reload or IS_RENDERING diff --git a/src/addon/resources/version_data/versions.json b/src/addon/resources/version_data/versions.json index 7fa1af02..2b3c4d3b 100644 --- a/src/addon/resources/version_data/versions.json +++ b/src/addon/resources/version_data/versions.json @@ -178,7 +178,60 @@ "See our FLIP Fluids Weekly Development notes #10 for a detailed changelog (flipfluids.com/blog)" ], "1.0.9": [ - "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!", + "### 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.", diff --git a/src/addon/types.py b/src/addon/types.py index 2125e217..f8bd7baf 100644 --- a/src/addon/types.py +++ b/src/addon/types.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -47,7 +47,7 @@ def object_types(self, context): ('FORCE_FIELD_TYPE_SURFACE', "Surface Force", "Force field directed towards an object's surface", 'OUTLINER_DATA_SURFACE', 1), ('FORCE_FIELD_TYPE_VOLUME', "Volume Force", "Force field directed to fill an object's volume", 'MESH_MONKEY', 2), ('FORCE_FIELD_TYPE_CURVE', "Curve Guide Force", "Force field directed along a curve object", 'FORCE_CURVE', 3), - ('FORCE_FIELD_TYPE_OTHER', "More coming soon! (in development)", "More force field modes such as vortex, turbublence, and programmable fields are in development! Try our experimental builds to test the latest features", 'FUND', 4), + ('FORCE_FIELD_TYPE_OTHER', "More modes are in development!", "More force field modes such as vortex, turbublence, and programmable fields are in development! Try our experimental builds to test the latest features", 'FUND', 4), ) # Uncomment/comment for experimental builds @@ -192,6 +192,11 @@ def object_types(self, context): ('MESHING_MODE_OUTSIDE_SURFACE', "Outside Surface", "Generate fluid-solid interface on the outside of the obstacle. Leaves a gap between the fluid surface and obstacle.") ) +velocity_transfer_methods = ( + ('VELOCITY_TRANSFER_METHOD_FLIP', "FLIP", "Choose FLIP for high energy, noisy, and chaotic simulations. Generally better for large scale simulations where noisy splashes are desirable."), + ('VELOCITY_TRANSFER_METHOD_APIC', "APIC", "Choose APIC for high vorticity, swirly, and stable simulations. Generally better for small scale simulations where reduced surface noise is desirable or for viscous simulations.") + ) + threading_modes = ( ('THREADING_MODE_AUTO_DETECT', "Auto-detect", "Automatically determine the number of threads, based on CPUs"), ('THREADING_MODE_FIXED', "Fixed", "Manually determine the number of threads") diff --git a/src/addon/ui/__init__.py b/src/addon/ui/__init__.py index 08bbf9cf..824eb96f 100644 --- a/src/addon/ui/__init__.py +++ b/src/addon/ui/__init__.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -68,8 +68,8 @@ def append_to_PHYSICS_PT_add_panel(self, context): ) if obj.flip_fluid.is_domain(): - row.prop(context.scene.flip_fluid, "show_render", icon="RESTRICT_RENDER_OFF", text="") row.prop(context.scene.flip_fluid, "show_viewport", icon="RESTRICT_VIEW_OFF", text="") + row.prop(context.scene.flip_fluid, "show_render", icon="RESTRICT_RENDER_OFF", text="") addon_prefs = vcu.get_addon_preferences(context) if addon_prefs.beginner_friendly_mode: @@ -79,20 +79,20 @@ def append_to_PHYSICS_PT_add_panel(self, context): row.prop(addon_prefs, "beginner_friendly_mode_tooltip", icon='QUESTION', emboss=False, text="") row.label(text="FLIP Fluids Beginner Friendly Mode is enabled") - # Uncomment/comment for experimental builds - """ + # Experimental Build Warning - box = self.layout.box() - column = box.column(align=True) - column.label(text="This is an experimental build of the FLIP Fluids addon", icon='ERROR') - column.label(text="Not for production. Use at your own risk.", icon='ERROR') - column.label(text="Please read before using:", icon='ERROR') - column.operator( - "wm.url_open", - text="Force Field Experimental Builds", - icon="WORLD" - ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Force-Field-Experimental-Builds" - """ + show_experimental_build_warning = False + if show_experimental_build_warning: + box = self.layout.box() + column = box.column(align=True) + column.label(text="This is an experimental build of the FLIP Fluids addon", icon='ERROR') + column.label(text="Not for production. Use at your own risk.", icon='ERROR') + column.label(text="Please read before using:", icon='ERROR') + column.operator( + "wm.url_open", + text="Force Field Experimental Builds", + icon="WORLD" + ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Experimental-Builds" is_saved = bool(bpy.data.filepath) if not is_saved and obj.flip_fluid.is_domain(): diff --git a/src/addon/ui/cache_object_ui.py b/src/addon/ui/cache_object_ui.py index a6c1e595..33e8df25 100644 --- a/src/addon/ui/cache_object_ui.py +++ b/src/addon/ui/cache_object_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/ui/domain_advanced_ui.py b/src/addon/ui/domain_advanced_ui.py index da690d1a..fce0da8e 100644 --- a/src/addon/ui/domain_advanced_ui.py +++ b/src/addon/ui/domain_advanced_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -35,6 +35,7 @@ def poll(cls, context): def draw(self, context): obj = vcu.get_active_object(context) aprops = obj.flip_fluid.domain.advanced + wprops = obj.flip_fluid.domain.world show_advanced = not vcu.get_addon_preferences(context).beginner_friendly_mode show_documentation = vcu.get_addon_preferences(context).show_documentation_in_ui @@ -45,43 +46,70 @@ def draw(self, context): text="Advanced Settings Documentation", icon="WORLD" ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Domain-Advanced-Settings" - column.operator( - "wm.url_open", - text="What are substeps?", - icon="WORLD" - ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Domain-Advanced-Settings#what-are-substeps-and-how-do-the-min-max-and-cfl-parameters-relate-to-each-other" - column.operator( - "wm.url_open", - text="What are applications of the PIC/FLIP Ratio?", - icon="WORLD" - ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Domain-Advanced-Settings#simulation-stability" - column = self.layout.column(align=True) + subbox = self.layout.box() + column = subbox.column(align=True) column.label(text="Frame Substeps:") + + if wprops.enable_surface_tension and aprops.min_max_time_steps_per_frame.value_max < wprops.minimum_surface_tension_substeps: + row = column.row(align=True) + row.alert = True + row.prop(aprops, "surface_tension_substeps_exceeded_tooltip", icon="QUESTION", emboss=False, text="") + row.label(text=" Warning: Not Enough Max Substeps") + row = column.row(align=True) row.prop(aprops.min_max_time_steps_per_frame, "value_min", text="Min") row.prop(aprops.min_max_time_steps_per_frame, "value_max", text="Max") + column.prop(aprops, "CFL_condition_number") if show_advanced: column.prop(aprops, "enable_adaptive_obstacle_time_stepping") column.prop(aprops, "enable_adaptive_force_field_time_stepping") - column = self.layout.column() + if show_documentation: + column = subbox.column(align=True) + column.operator( + "wm.url_open", + text="What are substeps?", + icon="WORLD" + ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Domain-Advanced-Settings#what-are-substeps-and-how-do-the-min-max-and-cfl-parameters-relate-to-each-other" + + subbox = self.layout.box() + column = subbox.column(align=True) + column.label(text="Simulation Method:") + row = column.row(align=True) + row.prop(aprops, "velocity_transfer_method", expand=True) + if aprops.velocity_transfer_method == 'VELOCITY_TRANSFER_METHOD_FLIP': + column.prop(aprops, "PICFLIP_ratio", slider=True) + else: + column.label(text="") + + if show_documentation: + column = subbox.column(align=True) + column.operator( + "wm.url_open", + text="What are applications of the PIC/FLIP Ratio?", + icon="WORLD" + ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Domain-Advanced-Settings#simulation-stability" + column.operator( + "wm.url_open", + text="FLIP vs APIC", + icon="WORLD" + ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Domain-Advanced-Settings#flip-vs-apic" + + subbox = self.layout.box() + column = subbox.column() column.label(text="Simulation Stability:") if show_advanced: row = column.row(align=True) row.prop(aprops, "particle_jitter_factor", slider=True) row.prop(aprops, "jitter_surface_particles") - column.prop(aprops, "PICFLIP_ratio", slider=True) - column = self.layout.column(align=True) - column.prop(aprops, "CFL_condition_number") - - if show_advanced: column.prop(aprops, "enable_extreme_velocity_removal") if show_advanced: - column = self.layout.column() + subbox = self.layout.box() + column = subbox.column() split = column.split(align=True) column_left = split.column(align=True) @@ -96,7 +124,7 @@ def draw(self, context): row.prop(aprops, "num_threads_fixed") if show_documentation: - column = self.layout.column(align=True) + column = subbox.column(align=True) column.operator( "wm.url_open", text="CPU usage is under 100%, is this normal?", @@ -114,7 +142,8 @@ def draw(self, context): column.prop(aprops, "reserve_temporary_grids") """ - column = self.layout.column(align=True) + subbox = self.layout.box() + column = subbox.column(align=True) column.separator() column.label(text="Warnings and Errors:") column.prop(aprops, "disable_changing_topology_warning") diff --git a/src/addon/ui/domain_cache_ui.py b/src/addon/ui/domain_cache_ui.py index a38ba2af..a34fdb69 100644 --- a/src/addon/ui/domain_cache_ui.py +++ b/src/addon/ui/domain_cache_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/ui/domain_debug_ui.py b/src/addon/ui/domain_debug_ui.py index 660689fc..40117a22 100644 --- a/src/addon/ui/domain_debug_ui.py +++ b/src/addon/ui/domain_debug_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -111,11 +111,20 @@ def draw(self, context): icon="TRIA_DOWN" if gprops.particle_debug_settings_expanded else "TRIA_RIGHT", icon_only=True, emboss=False - ) + ) if not gprops.particle_debug_settings_expanded: row.prop(gprops, "export_fluid_particles", text="") row.label(text="Fluid Particle Debugging:") + next_row = row.row() + next_row.alignment = 'RIGHT' + next_row.prop(gprops, "fluid_particles_visibility", + text="", + icon=vcu.get_hide_off_icon() if gprops.fluid_particles_visibility else vcu.get_hide_on_icon(), + emboss=False + ) + + if gprops.particle_debug_settings_expanded: box.prop(gprops, "export_fluid_particles") column = box.column(align=True) @@ -143,7 +152,6 @@ def draw(self, context): if show_advanced: box = self.layout.box() row = box.row(align=True) - row.alignment = 'LEFT' row.prop(gprops, "force_field_debug_settings_expanded", icon="TRIA_DOWN" if gprops.force_field_debug_settings_expanded else "TRIA_RIGHT", icon_only=True, @@ -153,6 +161,14 @@ def draw(self, context): row.prop(gprops, "export_force_field", text="") row.label(text="Force Field Debugging:") + next_row = row.row() + next_row.alignment = 'RIGHT' + next_row.prop(gprops, "force_field_visibility", + text="", + icon=vcu.get_hide_off_icon() if gprops.force_field_visibility else vcu.get_hide_on_icon(), + emboss=False + ) + if gprops.force_field_debug_settings_expanded: box.prop(gprops, "export_force_field") column = box.column(align=True) @@ -179,10 +195,19 @@ def draw(self, context): column.prop(gprops, "force_field_display_amount", text="") column.prop(gprops, "force_field_line_size", text="") - column = self.layout.column(align=True) - column.prop(gprops, "export_internal_obstacle_mesh") + box = self.layout.box() + row = box.row(align=True) + row.prop(gprops, "export_internal_obstacle_mesh") + next_row = row.row() + next_row.alignment = 'RIGHT' + next_row.prop(gprops, "internal_obstacle_mesh_visibility", + text="", + icon=vcu.get_hide_off_icon() if gprops.internal_obstacle_mesh_visibility else vcu.get_hide_on_icon(), + emboss=False + ) - column = self.layout.column(align=True) + box = self.layout.box() + column = box.column(align=True) column.prop(gprops, "display_console_output") diff --git a/src/addon/ui/domain_display_ui.py b/src/addon/ui/domain_display_ui.py index 102b4a9f..1df31168 100644 --- a/src/addon/ui/domain_display_ui.py +++ b/src/addon/ui/domain_display_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -334,6 +334,11 @@ def draw(self, context): text="Whitewater particles are not rendered in preview render", icon="WORLD" ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Scene-Troubleshooting#whitewater-particles-are-not-rendered-when-viewport-shading-is-set-to-rendered" + column.operator( + "wm.url_open", + text="Simulation meshes not appearing in viewport/render", + icon="WORLD" + ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Scene-Troubleshooting#simulation-meshes-are-not-appearing-in-the-viewport-andor-render" self.draw_surface_display_settings(context) self.draw_whitewater_display_settings(context) diff --git a/src/addon/ui/domain_materials_ui.py b/src/addon/ui/domain_materials_ui.py index 66a52bcb..e0f16762 100644 --- a/src/addon/ui/domain_materials_ui.py +++ b/src/addon/ui/domain_materials_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/ui/domain_presets_ui.py b/src/addon/ui/domain_presets_ui.py index 9eda1abb..bf9e6ba3 100644 --- a/src/addon/ui/domain_presets_ui.py +++ b/src/addon/ui/domain_presets_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/ui/domain_simulation_ui.py b/src/addon/ui/domain_simulation_ui.py index 4cc2d297..cb8fac55 100644 --- a/src/addon/ui/domain_simulation_ui.py +++ b/src/addon/ui/domain_simulation_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -82,6 +82,7 @@ def draw_bake_operator_UI_element(context, ui_box): if simprops.get_num_savestate_enums() < 100: column_left.prop(simprops, "selected_savestate", text="") else: + column_right.alert = False row = column_left.row(align=True) row.prop(simprops, "selected_savestate_int", text="Resume from frame") column_right.label(text=simprops.selected_savestate_int_label) @@ -283,7 +284,9 @@ def draw_resolution_settings(self, context, box): dprops = obj.flip_fluid.domain sprops = dprops.simulation wprops = dprops.world + aprops = dprops.advanced show_advanced = not vcu.get_addon_preferences(context).beginner_friendly_mode + show_documentation = vcu.get_addon_preferences(context).show_documentation_in_ui box.label(text="Domain Simulation Grid") @@ -322,6 +325,19 @@ def draw_resolution_settings(self, context, box): column.label(text=indent*" " + " Cache resolution: " + str(old_resolution)) column.label(text=indent*" " + " Current resolution: " + str(sprops.resolution)) + subbox = box.box() + column = subbox.column(align=True) + column.label(text="Simulation Method:") + row = subbox.row(align=True) + row.prop(aprops, "velocity_transfer_method", expand=True) + + if show_documentation: + column = subbox.column(align=True) + column.operator( + "wm.url_open", + text="FLIP vs APIC", + icon="WORLD" + ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Domain-Advanced-Settings#flip-vs-apic" subbox = box.box() column = subbox.column(align=True) @@ -345,6 +361,15 @@ def draw_resolution_settings(self, context, box): row.label(text="Domain Length = ") column_right.prop(wprops, "world_scale_absolute") + + if show_documentation: + column = subbox.column(align=True) + column.operator( + "wm.url_open", + text="World Scaling Documentation", + icon="WORLD" + ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Domain-World-Settings#world-size" + subbox = box.box() row = subbox.row() row.prop(sprops, "grid_info_expanded", @@ -417,6 +442,14 @@ def draw_resolution_settings(self, context, box): column_right.label(text=voxel_size_str) column_right.label(text=voxel_count_str) + if show_documentation: + column = subbox.column(align=True) + column.operator( + "wm.url_open", + text="What is the simulation grid?", + icon="WORLD" + ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Domain-Simulation-Settings#what-is-the-domain-simulation-grid" + def draw_time_settings(self, context, box): obj = vcu.get_active_object(context) diff --git a/src/addon/ui/domain_stats_ui.py b/src/addon/ui/domain_stats_ui.py index fb345dc2..1ef5266e 100644 --- a/src/addon/ui/domain_stats_ui.py +++ b/src/addon/ui/domain_stats_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/ui/domain_surface_ui.py b/src/addon/ui/domain_surface_ui.py index 73451895..969bffc9 100644 --- a/src/addon/ui/domain_surface_ui.py +++ b/src/addon/ui/domain_surface_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/ui/domain_ui.py b/src/addon/ui/domain_ui.py index 5f40a8ad..55a71c9f 100644 --- a/src/addon/ui/domain_ui.py +++ b/src/addon/ui/domain_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/ui/domain_whitewater_ui.py b/src/addon/ui/domain_whitewater_ui.py index 4b2188ed..3d67a4e7 100644 --- a/src/addon/ui/domain_whitewater_ui.py +++ b/src/addon/ui/domain_whitewater_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -69,6 +69,11 @@ def draw(self, context): text="Whitewater particles are not exported to Alembic", icon="WORLD" ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Alembic-Export-Support#rendering-alembic-whitewater-on-a-render-farm" + column.operator( + "wm.url_open", + text="Whitewater rendering tips", + icon="WORLD" + ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Domain-Whitewater-Settings#whitewater-rendering-tips" column = self.layout.column(align=True) diff --git a/src/addon/ui/domain_world_ui.py b/src/addon/ui/domain_world_ui.py index 17001cc7..c2a8c2db 100644 --- a/src/addon/ui/domain_world_ui.py +++ b/src/addon/ui/domain_world_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -195,11 +195,6 @@ def draw(self, context): text="Force Field Resolution", icon="WORLD" ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Domain-World-Settings#force-field-resolution" - column.operator( - "wm.url_open", - text="Force Field Experimental Builds", - icon="WORLD" - ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Force-Field-Experimental-Builds" column.operator( "wm.url_open", text="Force Field Example Scenes", @@ -223,6 +218,7 @@ def draw(self, context): column_left = split.column(align=True) column_left.prop(wprops, "enable_viscosity") column_left.label(text="") + column_left.label(text="") row = column_left.row(align=True) row.alignment='RIGHT' row.enabled = wprops.enable_viscosity @@ -235,6 +231,7 @@ def draw(self, context): column_right.enabled = wprops.enable_viscosity column_right.prop(wprops, "viscosity", text="Base") column_right.prop(wprops, "viscosity_exponent", text="Exponent") + column_right.prop(wprops, "viscosity_solver_error_tolerance", text="Accuracy", slider=True) column_right.label(text=viscosity_str) if show_documentation: @@ -284,6 +281,12 @@ def draw(self, context): column_right.label(text=surface_tension_str) column_right.label(text=str(wprops.minimum_surface_tension_substeps)) + if wprops.enable_surface_tension and wprops.minimum_surface_tension_substeps > aprops.min_max_time_steps_per_frame.value_max: + row = column.row(align=True) + row.alert = True + row.prop(wprops, "surface_tension_substeps_exceeded_tooltip", icon="QUESTION", emboss=False, text="") + row.label(text=" Warning: Too Many Substeps") + if show_documentation: column = box.column(align=True) column.operator( diff --git a/src/addon/ui/fluid_ui.py b/src/addon/ui/fluid_ui.py index 421ef963..6cdcd330 100644 --- a/src/addon/ui/fluid_ui.py +++ b/src/addon/ui/fluid_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/ui/force_field_ui.py b/src/addon/ui/force_field_ui.py index 7d4eacf2..c32cd54c 100644 --- a/src/addon/ui/force_field_ui.py +++ b/src/addon/ui/force_field_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -81,9 +81,9 @@ def draw(self, context): column.label(text="Try out our experimental builds for the latest features!") column.operator( "wm.url_open", - text="Force Field Experimental Builds", + text="Experimental Builds", icon="WORLD" - ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Force-Field-Experimental-Builds" + ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Experimental-Builds" return if show_documentation: diff --git a/src/addon/ui/helper_ui.py b/src/addon/ui/helper_ui.py index 15d66879..ee06170b 100644 --- a/src/addon/ui/helper_ui.py +++ b/src/addon/ui/helper_ui.py @@ -128,18 +128,32 @@ def draw(self, context): column = box.column(align=True) column.operator("flip_fluid_operators.helper_remove_objects", text="Remove") - column = box.column(align=True) + column = box.column() column.label(text="Object Display:") row = column.row(align=True) row.operator( "flip_fluid_operators.helper_set_object_viewport_display", - text="Solid" + text="Solid", + icon="MESH_CUBE" if vcu.is_blender_28() else "NONE" ).display_mode="DISPLAY_MODE_SOLID" row.operator( "flip_fluid_operators.helper_set_object_viewport_display", - text="Wireframe" + text="Wireframe", + icon="CUBE" if vcu.is_blender_28() else "NONE" ).display_mode="DISPLAY_MODE_WIREFRAME" + row = column.row(align=True) + row.operator( + "flip_fluid_operators.helper_set_object_render_display", + text="Show Render", + icon="RESTRICT_RENDER_OFF" if vcu.is_blender_28() else "NONE" + ).hide_render=False + row.operator( + "flip_fluid_operators.helper_set_object_render_display", + text="Hide Render", + icon="RESTRICT_RENDER_ON" if vcu.is_blender_28() else "NONE" + ).hide_render=True + # # Select Objects # @@ -232,10 +246,19 @@ def draw(self, context): row = column.row(align=True) row.operator("flip_fluid_operators.helper_command_line_bake") row.operator("flip_fluid_operators.helper_command_line_bake_to_clipboard", text="", icon='COPYDOWN') + column = box.column(align=True) row = column.row(align=True) row.operator("flip_fluid_operators.helper_command_line_render") row.operator("flip_fluid_operators.helper_command_line_render_to_clipboard", text="", icon='COPYDOWN') + system = platform.system() + if system == "Windows": + row = column.row(align=True) + row.operator("flip_fluid_operators.helper_cmd_render_to_scriptfile") + row.operator("flip_fluid_operators.helper_run_scriptfile", text="", icon='PLAY') + row.operator("flip_fluid_operators.helper_open_outputfolder", text="", icon='FILE_FOLDER') + column.separator() + # # Beginner Tools # @@ -263,6 +286,11 @@ def draw(self, context): ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Helper-Menu-Settings" column.separator() + column.operator( + "wm.url_open", + text="Video Learning Series", + icon="WORLD" + ).url = "https://github.com/rlguy/Blender-FLIP-Fluids/wiki/Video-Learning-Series" column.operator( "wm.url_open", text="Documentation and Wiki", @@ -410,8 +438,17 @@ def draw(self, context): row = column.row(align=True) row.operator("flip_fluid_operators.helper_command_line_render", text="Launch Command Line Render") row.operator("flip_fluid_operators.helper_command_line_render_to_clipboard", text="", icon='COPYDOWN') - column.separator() - column.separator() + + system = platform.system() + if system == "Windows": + row = column.row(align=True) + row.operator("flip_fluid_operators.helper_cmd_render_to_scriptfile") + row.operator("flip_fluid_operators.helper_run_scriptfile", text="", icon='PLAY') + row.operator("flip_fluid_operators.helper_open_outputfolder", text="", icon='FILE_FOLDER') + + column.separator() + column.separator() + if vcu.is_blender_28(): lock_interface = context.scene.render.use_lock_interface diff --git a/src/addon/ui/inflow_ui.py b/src/addon/ui/inflow_ui.py index f5f5d736..0f469e61 100644 --- a/src/addon/ui/inflow_ui.py +++ b/src/addon/ui/inflow_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/ui/none_ui.py b/src/addon/ui/none_ui.py index 426b7ff6..b6f68e99 100644 --- a/src/addon/ui/none_ui.py +++ b/src/addon/ui/none_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/ui/obstacle_ui.py b/src/addon/ui/obstacle_ui.py index f7852fbd..deb9c7a3 100644 --- a/src/addon/ui/obstacle_ui.py +++ b/src/addon/ui/obstacle_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/ui/outflow_ui.py b/src/addon/ui/outflow_ui.py index cd179faf..a04590c2 100644 --- a/src/addon/ui/outflow_ui.py +++ b/src/addon/ui/outflow_ui.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/utils/__init__.py b/src/addon/utils/__init__.py index fbbfde69..f384f36f 100644 --- a/src/addon/utils/__init__.py +++ b/src/addon/utils/__init__.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/utils/api_workaround_utils.py b/src/addon/utils/api_workaround_utils.py index ceda2def..06877579 100644 --- a/src/addon/utils/api_workaround_utils.py +++ b/src/addon/utils/api_workaround_utils.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -66,3 +66,19 @@ def frame_change_post_apply_T71908_workaround(context, depsgraph=None): if obj.modifiers[i].type == 'OCEAN': obj.modifiers[i].time = obj_eval.modifiers[i].time print("updated", obj.modifiers[i]) + + +# In some versions of Blender the viewport rendered view is +# not updated to display and object if the object's 'hide_render' +# property has changed or ray visibility has changed via Python. +# Toggling the object's hide_viewport option on and off +# is a workaround to get the viewport to update. +# +# Note: toggling hide_viewport will deselect the object, so this workaround +# will also re-select the object if needed. +def toggle_viewport_visibility_to_update_rendered_viewport_workaround(bl_object): + is_selected = vcu.select_get(bl_object) + vcu.toggle_outline_eye_icon(bl_object) + vcu.toggle_outline_eye_icon(bl_object) + if is_selected: + vcu.select_set(bl_object, True) \ No newline at end of file diff --git a/src/addon/utils/cache_utils.py b/src/addon/utils/cache_utils.py index 6bef3b90..2885fbbc 100644 --- a/src/addon/utils/cache_utils.py +++ b/src/addon/utils/cache_utils.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/utils/export_utils.py b/src/addon/utils/export_utils.py index fbbf3464..99a5c34f 100644 --- a/src/addon/utils/export_utils.py +++ b/src/addon/utils/export_utils.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -56,8 +56,8 @@ def is_property_animated(obj, prop_name, index = 0): return False for fcurve in anim_data.action.fcurves: - path = fcurve.data_path.split(".")[-1] - if path == prop_name and fcurve.array_index == index: + path = fcurve.data_path + if path.endswith(prop_name) and fcurve.array_index == index: return True return False @@ -83,8 +83,8 @@ def is_vector_animated(obj, prop_name, vector_size = 3): def get_property_fcurve(obj, prop_name, index = 0): anim_data = obj.animation_data for fcurve in anim_data.action.fcurves: - path = fcurve.data_path.split(".")[-1] - if path == prop_name and fcurve.array_index == index: + path = fcurve.data_path + if path.endswith(prop_name) and fcurve.array_index == index: return fcurve @@ -120,7 +120,8 @@ def get_property_data_dict(obj, prop_group, prop_name, index = None): else: return {'is_animated' : True, 'data' : values} else: - value = getattr(prop_group, prop_name) + prop_name_suffix = prop_name.split(".")[-1] + value = getattr(prop_group, prop_name_suffix) if is_index_set: value = value[index] return {'is_animated' : False, 'data' : value} @@ -196,8 +197,15 @@ def get_vector_property_data_dict(obj, prop_group, prop_name, vector_size = 3): def get_min_max_property_data_dict(obj, prop_group, prop_name): prop_group = getattr(prop_group, prop_name) - min_dict = get_property_data_dict(obj, prop_group, "value_min") - max_dict = get_property_data_dict(obj, prop_group, "value_max") + + # Multiple properties attached to a single object may have + # 'value_min' or 'value_max' as the name. In order to correctly + # search for the property, set the identifier as a path + # Ex: prop_name.value_min + identifier_min = prop_name + ".value_min" + identifier_max = prop_name + ".value_max" + min_dict = get_property_data_dict(obj, prop_group, identifier_min) + max_dict = get_property_data_dict(obj, prop_group, identifier_max) is_animated = min_dict['is_animated'] or max_dict['is_animated'] if is_animated: diff --git a/src/addon/utils/installation_utils.py b/src/addon/utils/installation_utils.py index 5c257903..cfaf6199 100644 --- a/src/addon/utils/installation_utils.py +++ b/src/addon/utils/installation_utils.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/utils/preset_utils.py b/src/addon/utils/preset_utils.py index 31ca9cf4..4894db80 100644 --- a/src/addon/utils/preset_utils.py +++ b/src/addon/utils/preset_utils.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/utils/ui_utils.py b/src/addon/utils/ui_utils.py index d7e84879..9d89a3d8 100644 --- a/src/addon/utils/ui_utils.py +++ b/src/addon/utils/ui_utils.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/addon/utils/version_compatibility_utils.py b/src/addon/utils/version_compatibility_utils.py index bd96c970..a8600ce9 100644 --- a/src/addon/utils/version_compatibility_utils.py +++ b/src/addon/utils/version_compatibility_utils.py @@ -1,5 +1,5 @@ # Blender FLIP Fluids Add-on -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -433,4 +433,16 @@ def get_file_folder_icon(): if is_blender_28(): return "FILEBROWSER" else: - return "FILESEL" \ No newline at end of file + return "FILESEL" + +def get_hide_off_icon(): + if is_blender_28(): + return "HIDE_OFF" + else: + return "RESTRICT_VIEW_OFF" + +def get_hide_on_icon(): + if is_blender_28(): + return "HIDE_ON" + else: + return "RESTRICT_VIEW_ON" \ No newline at end of file diff --git a/src/engine/aabb.cpp b/src/engine/aabb.cpp index bd5b6744..8a4a0110 100644 --- a/src/engine/aabb.cpp +++ b/src/engine/aabb.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/aabb.h b/src/engine/aabb.h index 7e38e1e3..68fdec6e 100644 --- a/src/engine/aabb.h +++ b/src/engine/aabb.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/array3d.h b/src/engine/array3d.h index 292bb4ce..36aab402 100644 --- a/src/engine/array3d.h +++ b/src/engine/array3d.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/arrayview3d.h b/src/engine/arrayview3d.h index 80e7f46b..b67c01de 100644 --- a/src/engine/arrayview3d.h +++ b/src/engine/arrayview3d.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/blockarray3d.h b/src/engine/blockarray3d.h index 9a94f37c..18399c89 100644 --- a/src/engine/blockarray3d.h +++ b/src/engine/blockarray3d.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/boundedbuffer.h b/src/engine/boundedbuffer.h index f1ed191f..7c734812 100644 --- a/src/engine/boundedbuffer.h +++ b/src/engine/boundedbuffer.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/c_bindings/aabb_c.h b/src/engine/c_bindings/aabb_c.h index 1896c789..60565393 100644 --- a/src/engine/c_bindings/aabb_c.h +++ b/src/engine/c_bindings/aabb_c.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/c_bindings/cbindings.cpp b/src/engine/c_bindings/cbindings.cpp index 5bb457ad..4c1ec0a9 100644 --- a/src/engine/c_bindings/cbindings.cpp +++ b/src/engine/c_bindings/cbindings.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/c_bindings/cbindings.h b/src/engine/c_bindings/cbindings.h index 3514d82f..ad57aa18 100644 --- a/src/engine/c_bindings/cbindings.h +++ b/src/engine/c_bindings/cbindings.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/c_bindings/diffuseparticle_c.h b/src/engine/c_bindings/diffuseparticle_c.h index 699b3127..f51adf64 100644 --- a/src/engine/c_bindings/diffuseparticle_c.h +++ b/src/engine/c_bindings/diffuseparticle_c.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/c_bindings/fluidsimulation_c.cpp b/src/engine/c_bindings/fluidsimulation_c.cpp index cc6cf33a..c5ce5d68 100644 --- a/src/engine/c_bindings/fluidsimulation_c.cpp +++ b/src/engine/c_bindings/fluidsimulation_c.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -1766,6 +1766,21 @@ extern "C" { ); } + EXPORTDLL double FluidSimulation_get_viscosity_solver_error_tolerance(FluidSimulation* obj, int *err) { + return CBindings::safe_execute_method_ret_0param( + obj, &FluidSimulation::getViscositySolverErrorTolerance, err + ); + } + + EXPORTDLL void FluidSimulation_set_viscosity_solver_error_tolerance(FluidSimulation* obj, + double tol, + int *err) { + CBindings::safe_execute_method_void_1param( + obj, &FluidSimulation::setViscositySolverErrorTolerance, tol, err + ); + } + + EXPORTDLL double FluidSimulation_get_surface_tension(FluidSimulation* obj, int *err) { return CBindings::safe_execute_method_ret_0param( obj, &FluidSimulation::getSurfaceTension, err @@ -1961,6 +1976,34 @@ extern "C" { ); } + EXPORTDLL void FluidSimulation_set_velocity_transfer_method_FLIP(FluidSimulation* obj, + int *err) { + CBindings::safe_execute_method_void_0param( + obj, &FluidSimulation::setVelocityTransferMethodFLIP, err + ); + } + + EXPORTDLL void FluidSimulation_set_velocity_transfer_method_APIC(FluidSimulation* obj, + int *err) { + CBindings::safe_execute_method_void_0param( + obj, &FluidSimulation::setVelocityTransferMethodAPIC, err + ); + } + + EXPORTDLL int FluidSimulation_is_velocity_transfer_method_FLIP(FluidSimulation* obj, + int *err) { + return CBindings::safe_execute_method_ret_0param( + obj, &FluidSimulation::isVelocityTransferMethodFLIP, err + ); + } + + EXPORTDLL int FluidSimulation_is_velocity_transfer_method_APIC(FluidSimulation* obj, + int *err) { + return CBindings::safe_execute_method_ret_0param( + obj, &FluidSimulation::isVelocityTransferMethodAPIC, err + ); + } + EXPORTDLL double FluidSimulation_get_PICFLIP_ratio(FluidSimulation* obj, int *err) { return CBindings::safe_execute_method_ret_0param( obj, &FluidSimulation::getPICFLIPRatio, err @@ -1974,6 +2017,19 @@ extern "C" { ); } + EXPORTDLL double FluidSimulation_get_PICAPIC_ratio(FluidSimulation* obj, int *err) { + return CBindings::safe_execute_method_ret_0param( + obj, &FluidSimulation::getPICAPICRatio, err + ); + } + + EXPORTDLL void FluidSimulation_set_PICAPIC_ratio(FluidSimulation* obj, + double ratio, int *err) { + CBindings::safe_execute_method_void_1param( + obj, &FluidSimulation::setPICAPICRatio, ratio, err + ); + } + EXPORTDLL void FluidSimulation_get_preferred_gpu_device(FluidSimulation* obj, char *device_name, int *err) { *err = CBindings::SUCCESS; @@ -2157,21 +2213,6 @@ extern "C" { ); } - EXPORTDLL void FluidSimulation_get_diffuse_particles( - FluidSimulation* obj, - int startidx, int endidx, - DiffuseParticle_t *out, int *err) { - - std::vector dps = CBindings::safe_execute_method_ret_2param( - obj, &FluidSimulation::getDiffuseParticles, - startidx, endidx, err - ); - - for (unsigned int i = 0; i < dps.size(); i++) { - out[i] = CBindings::to_struct(dps[i]); - } - } - EXPORTDLL void FluidSimulation_get_diffuse_particle_positions( FluidSimulation* obj, int startidx, int endidx, @@ -2709,6 +2750,39 @@ extern "C" { } } + EXPORTDLL void FluidSimulation_get_marker_particle_affinex_data_range(FluidSimulation* obj, + int start_idx, int end_idx, char *c_data, int *err) { + *err = CBindings::SUCCESS; + try { + obj->getMarkerParticleAffineXDataRange(start_idx, end_idx, c_data); + } catch (std::exception &ex) { + CBindings::set_error_message(ex); + *err = CBindings::FAIL; + } + } + + EXPORTDLL void FluidSimulation_get_marker_particle_affiney_data_range(FluidSimulation* obj, + int start_idx, int end_idx, char *c_data, int *err) { + *err = CBindings::SUCCESS; + try { + obj->getMarkerParticleAffineYDataRange(start_idx, end_idx, c_data); + } catch (std::exception &ex) { + CBindings::set_error_message(ex); + *err = CBindings::FAIL; + } + } + + EXPORTDLL void FluidSimulation_get_marker_particle_affinez_data_range(FluidSimulation* obj, + int start_idx, int end_idx, char *c_data, int *err) { + *err = CBindings::SUCCESS; + try { + obj->getMarkerParticleAffineZDataRange(start_idx, end_idx, c_data); + } catch (std::exception &ex) { + CBindings::set_error_message(ex); + *err = CBindings::FAIL; + } + } + EXPORTDLL void FluidSimulation_get_diffuse_particle_position_data_range(FluidSimulation* obj, int start_idx, int end_idx, char *c_data, int *err) { *err = CBindings::SUCCESS; @@ -2821,6 +2895,14 @@ extern "C" { ); } + EXPORTDLL void FluidSimulation_load_marker_particle_affine_data(FluidSimulation* obj, + FluidSimulationMarkerParticleAffineData data, + int *err) { + CBindings::safe_execute_method_void_1param( + obj, &FluidSimulation::loadMarkerParticleAffineData, data, err + ); + } + EXPORTDLL void FluidSimulation_load_diffuse_particle_data(FluidSimulation* obj, FluidSimulationDiffuseParticleData data, int *err) { diff --git a/src/engine/c_bindings/forcefield_c.cpp b/src/engine/c_bindings/forcefield_c.cpp index 367a0b4f..f1a56162 100644 --- a/src/engine/c_bindings/forcefield_c.cpp +++ b/src/engine/c_bindings/forcefield_c.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/c_bindings/forcefieldcurve_c.cpp b/src/engine/c_bindings/forcefieldcurve_c.cpp index 241677f6..4633ae4c 100644 --- a/src/engine/c_bindings/forcefieldcurve_c.cpp +++ b/src/engine/c_bindings/forcefieldcurve_c.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/c_bindings/forcefieldgrid_c.cpp b/src/engine/c_bindings/forcefieldgrid_c.cpp index 2f25acbd..f1441406 100644 --- a/src/engine/c_bindings/forcefieldgrid_c.cpp +++ b/src/engine/c_bindings/forcefieldgrid_c.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/c_bindings/forcefieldpoint_c.cpp b/src/engine/c_bindings/forcefieldpoint_c.cpp index 263d6a9f..89a2132a 100644 --- a/src/engine/c_bindings/forcefieldpoint_c.cpp +++ b/src/engine/c_bindings/forcefieldpoint_c.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/c_bindings/forcefieldsurface_c.cpp b/src/engine/c_bindings/forcefieldsurface_c.cpp index 4e32b43e..b70bbef0 100644 --- a/src/engine/c_bindings/forcefieldsurface_c.cpp +++ b/src/engine/c_bindings/forcefieldsurface_c.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/c_bindings/forcefieldvolume_c.cpp b/src/engine/c_bindings/forcefieldvolume_c.cpp index 0a290516..023fffc8 100644 --- a/src/engine/c_bindings/forcefieldvolume_c.cpp +++ b/src/engine/c_bindings/forcefieldvolume_c.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/c_bindings/gridindex_c.h b/src/engine/c_bindings/gridindex_c.h index acfffb82..c0e51d88 100644 --- a/src/engine/c_bindings/gridindex_c.h +++ b/src/engine/c_bindings/gridindex_c.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/c_bindings/markerparticle_c.h b/src/engine/c_bindings/markerparticle_c.h index c369165b..608a49c1 100644 --- a/src/engine/c_bindings/markerparticle_c.h +++ b/src/engine/c_bindings/markerparticle_c.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/c_bindings/meshfluidsource_c.cpp b/src/engine/c_bindings/meshfluidsource_c.cpp index e3d935db..65371bfe 100644 --- a/src/engine/c_bindings/meshfluidsource_c.cpp +++ b/src/engine/c_bindings/meshfluidsource_c.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/c_bindings/meshobject_c.cpp b/src/engine/c_bindings/meshobject_c.cpp index e59d53d2..86ffa815 100644 --- a/src/engine/c_bindings/meshobject_c.cpp +++ b/src/engine/c_bindings/meshobject_c.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/c_bindings/openclutils_c.cpp b/src/engine/c_bindings/openclutils_c.cpp index fd774ff5..f55effff 100644 --- a/src/engine/c_bindings/openclutils_c.cpp +++ b/src/engine/c_bindings/openclutils_c.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/c_bindings/vector3_c.h b/src/engine/c_bindings/vector3_c.h index 96d3fca3..ce43b2f9 100644 --- a/src/engine/c_bindings/vector3_c.h +++ b/src/engine/c_bindings/vector3_c.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/clscalarfield.cpp b/src/engine/clscalarfield.cpp index 9bd8442f..8947ac78 100644 --- a/src/engine/clscalarfield.cpp +++ b/src/engine/clscalarfield.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/clscalarfield.h b/src/engine/clscalarfield.h index e2b572c6..4dec175a 100644 --- a/src/engine/clscalarfield.h +++ b/src/engine/clscalarfield.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/collision.cpp b/src/engine/collision.cpp index 762081e5..f91757d8 100644 --- a/src/engine/collision.cpp +++ b/src/engine/collision.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/collision.h b/src/engine/collision.h index 693c8e57..07a71bd2 100644 --- a/src/engine/collision.h +++ b/src/engine/collision.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/diffuseparticle.h b/src/engine/diffuseparticle.h index 5c6f2b36..35a3250a 100644 --- a/src/engine/diffuseparticle.h +++ b/src/engine/diffuseparticle.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/diffuseparticlesimulation.cpp b/src/engine/diffuseparticlesimulation.cpp index 552b9783..34a5d01b 100644 --- a/src/engine/diffuseparticlesimulation.cpp +++ b/src/engine/diffuseparticlesimulation.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -28,7 +28,6 @@ SOFTWARE. #include "threadutils.h" #include "interpolation.h" -#include "diffuseparticle.h" #include "markerparticle.h" #include "meshlevelset.h" #include "particlelevelset.h" @@ -38,6 +37,12 @@ SOFTWARE. DiffuseParticleSimulation::DiffuseParticleSimulation() { double inf = std::numeric_limits::infinity(); _emitterGenerationBounds = AABB(-inf, -inf, -inf, inf, inf, inf); + + _diffuseParticles.addAttributeVector3("POSITION"); + _diffuseParticles.addAttributeVector3("VELOCITY"); + _diffuseParticles.addAttributeFloat("LIFETIME"); + _diffuseParticles.addAttributeChar("TYPE"); + _diffuseParticles.addAttributeUChar("ID"); } DiffuseParticleSimulation::~DiffuseParticleSimulation() { @@ -186,7 +191,7 @@ bool DiffuseParticleSimulation::isBoundaryDustEmissionEnabled() { return _isBoundaryDustEmissionEnabled; } -FragmentedVector* DiffuseParticleSimulation::getDiffuseParticles() { +ParticleSystem* DiffuseParticleSimulation::getDiffuseParticles() { return &_diffuseParticles; } @@ -194,42 +199,6 @@ int DiffuseParticleSimulation::getNumDiffuseParticles() { return _diffuseParticles.size(); } -void DiffuseParticleSimulation:: - setDiffuseParticles(std::vector &particles) { - _diffuseParticles.clear(); - _diffuseParticles.shrink_to_fit(); - _diffuseParticles.reserve((unsigned int)particles.size()); - for (size_t i = 0; i < particles.size(); i++) { - _diffuseParticles.push_back(particles[i]); - } -} - -void DiffuseParticleSimulation:: - setDiffuseParticles(FragmentedVector &particles) { - _diffuseParticles.clear(); - _diffuseParticles.shrink_to_fit(); - _diffuseParticles.reserve(particles.size()); - for (unsigned int i = 0; i < particles.size(); i++) { - _diffuseParticles.push_back(particles[i]); - } -} - -void DiffuseParticleSimulation:: - addDiffuseParticles(std::vector &particles) { - _diffuseParticles.reserve((unsigned int)(_diffuseParticles.size() + particles.size())); - for (size_t i = 0; i < particles.size(); i++) { - _diffuseParticles.push_back(particles[i]); - } -} - -void DiffuseParticleSimulation:: - addDiffuseParticles(FragmentedVector &particles) { - _diffuseParticles.reserve(_diffuseParticles.size() + particles.size()); - for (unsigned int i = 0; i < particles.size(); i++) { - _diffuseParticles.push_back(particles[i]); - } -} - int DiffuseParticleSimulation::getMaxNumDiffuseParticles() { return _maxNumDiffuseParticles; } @@ -604,20 +573,25 @@ void DiffuseParticleSimulation::getDiffuseParticleFileDataWWP(std::vector positions.reserve(_diffuseParticles.size()); ids.reserve(_diffuseParticles.size()); + std::vector *particlePositions; + std::vector *particleIds; + _diffuseParticles.getAttributeValues("POSITION", particlePositions); + _diffuseParticles.getAttributeValues("ID", particleIds); + if (_isMeshingVolumeSet) { std::vector isSolid; - _meshingVolumeSDF->trilinearInterpolateSolidPoints(_diffuseParticles, isSolid); - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { + _meshingVolumeSDF->trilinearInterpolateSolidPoints(*particlePositions, isSolid); + for (size_t i = 0; i < particlePositions->size(); i++) { if (isSolid[i]) { continue; } - positions.push_back(_diffuseParticles[i].position * _domainScale + _domainOffset); - ids.push_back(_diffuseParticles[i].id); + positions.push_back(particlePositions->at(i) * _domainScale + _domainOffset); + ids.push_back(particleIds->at(i)); } } else { for (int i = 0; i < (int)_diffuseParticles.size(); i++) { - positions.push_back(_diffuseParticles[i].position * _domainScale + _domainOffset); - ids.push_back(_diffuseParticles[i].id); + positions.push_back(particlePositions->at(i) * _domainScale + _domainOffset); + ids.push_back(particleIds->at(i)); } } @@ -629,23 +603,31 @@ void DiffuseParticleSimulation::getFoamParticleFileDataWWP(std::vector &da std::vector ids; positions.reserve(_diffuseParticles.size()); ids.reserve(_diffuseParticles.size()); + + std::vector *particlePositions; + std::vector *particleIds; + std::vector *particleTypes; + _diffuseParticles.getAttributeValues("POSITION", particlePositions); + _diffuseParticles.getAttributeValues("ID", particleIds); + _diffuseParticles.getAttributeValues("TYPE", particleTypes); + if (_isMeshingVolumeSet) { std::vector isSolid; - _meshingVolumeSDF->trilinearInterpolateSolidPoints(_diffuseParticles, isSolid); + _meshingVolumeSDF->trilinearInterpolateSolidPoints(*particlePositions, isSolid); for (int i = 0; i < (int)_diffuseParticles.size(); i++) { if (isSolid[i]) { continue; } - if (_diffuseParticles[i].type == DiffuseParticleType::foam) { - positions.push_back(_diffuseParticles[i].position * _domainScale + _domainOffset); - ids.push_back(_diffuseParticles[i].id); + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::foam) { + positions.push_back(particlePositions->at(i) * _domainScale + _domainOffset); + ids.push_back(particleIds->at(i)); } } } else { for (int i = 0; i < (int)_diffuseParticles.size(); i++) { - if (_diffuseParticles[i].type == DiffuseParticleType::foam) { - positions.push_back(_diffuseParticles[i].position * _domainScale + _domainOffset); - ids.push_back(_diffuseParticles[i].id); + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::foam) { + positions.push_back(particlePositions->at(i) * _domainScale + _domainOffset); + ids.push_back(particleIds->at(i)); } } } @@ -658,23 +640,31 @@ void DiffuseParticleSimulation::getBubbleParticleFileDataWWP(std::vector & std::vector ids; positions.reserve(_diffuseParticles.size()); ids.reserve(_diffuseParticles.size()); + + std::vector *particlePositions; + std::vector *particleIds; + std::vector *particleTypes; + _diffuseParticles.getAttributeValues("POSITION", particlePositions); + _diffuseParticles.getAttributeValues("ID", particleIds); + _diffuseParticles.getAttributeValues("TYPE", particleTypes); + if (_isMeshingVolumeSet) { std::vector isSolid; - _meshingVolumeSDF->trilinearInterpolateSolidPoints(_diffuseParticles, isSolid); - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { + _meshingVolumeSDF->trilinearInterpolateSolidPoints(*particlePositions, isSolid); + for (size_t i = 0; i < _diffuseParticles.size(); i++) { if (isSolid[i]) { continue; } - if (_diffuseParticles[i].type == DiffuseParticleType::bubble) { - positions.push_back(_diffuseParticles[i].position * _domainScale + _domainOffset); - ids.push_back(_diffuseParticles[i].id); + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::bubble) { + positions.push_back(particlePositions->at(i) * _domainScale + _domainOffset); + ids.push_back(particleIds->at(i)); } } } else { - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { - if (_diffuseParticles[i].type == DiffuseParticleType::bubble) { - positions.push_back(_diffuseParticles[i].position * _domainScale + _domainOffset); - ids.push_back(_diffuseParticles[i].id); + for (size_t i = 0; i < _diffuseParticles.size(); i++) { + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::bubble) { + positions.push_back(particlePositions->at(i) * _domainScale + _domainOffset); + ids.push_back(particleIds->at(i)); } } } @@ -687,23 +677,31 @@ void DiffuseParticleSimulation::getSprayParticleFileDataWWP(std::vector &d std::vector ids; positions.reserve(_diffuseParticles.size()); ids.reserve(_diffuseParticles.size()); + + std::vector *particlePositions; + std::vector *particleIds; + std::vector *particleTypes; + _diffuseParticles.getAttributeValues("POSITION", particlePositions); + _diffuseParticles.getAttributeValues("ID", particleIds); + _diffuseParticles.getAttributeValues("TYPE", particleTypes); + if (_isMeshingVolumeSet) { std::vector isSolid; - _meshingVolumeSDF->trilinearInterpolateSolidPoints(_diffuseParticles, isSolid); - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { + _meshingVolumeSDF->trilinearInterpolateSolidPoints(*particlePositions, isSolid); + for (size_t i = 0; i < _diffuseParticles.size(); i++) { if (isSolid[i]) { continue; } - if (_diffuseParticles[i].type == DiffuseParticleType::spray) { - positions.push_back(_diffuseParticles[i].position * _domainScale + _domainOffset); - ids.push_back(_diffuseParticles[i].id); + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::spray) { + positions.push_back(particlePositions->at(i) * _domainScale + _domainOffset); + ids.push_back(particleIds->at(i)); } } } else { - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { - if (_diffuseParticles[i].type == DiffuseParticleType::spray) { - positions.push_back(_diffuseParticles[i].position * _domainScale + _domainOffset); - ids.push_back(_diffuseParticles[i].id); + for (size_t i = 0; i < _diffuseParticles.size(); i++) { + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::spray) { + positions.push_back(particlePositions->at(i) * _domainScale + _domainOffset); + ids.push_back(particleIds->at(i)); } } } @@ -716,23 +714,31 @@ void DiffuseParticleSimulation::getDustParticleFileDataWWP(std::vector &da std::vector ids; positions.reserve(_diffuseParticles.size()); ids.reserve(_diffuseParticles.size()); + + std::vector *particlePositions; + std::vector *particleIds; + std::vector *particleTypes; + _diffuseParticles.getAttributeValues("POSITION", particlePositions); + _diffuseParticles.getAttributeValues("ID", particleIds); + _diffuseParticles.getAttributeValues("TYPE", particleTypes); + if (_isMeshingVolumeSet) { std::vector isSolid; - _meshingVolumeSDF->trilinearInterpolateSolidPoints(_diffuseParticles, isSolid); - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { + _meshingVolumeSDF->trilinearInterpolateSolidPoints(*particlePositions, isSolid); + for (size_t i = 0; i < _diffuseParticles.size(); i++) { if (isSolid[i]) { continue; } - if (_diffuseParticles[i].type == DiffuseParticleType::dust) { - positions.push_back(_diffuseParticles[i].position * _domainScale + _domainOffset); - ids.push_back(_diffuseParticles[i].id); + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::dust) { + positions.push_back(particlePositions->at(i) * _domainScale + _domainOffset); + ids.push_back(particleIds->at(i)); } } } else { - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { - if (_diffuseParticles[i].type == DiffuseParticleType::dust) { - positions.push_back(_diffuseParticles[i].position * _domainScale + _domainOffset); - ids.push_back(_diffuseParticles[i].id); + for (size_t i = 0; i < _diffuseParticles.size(); i++) { + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::dust) { + positions.push_back(particlePositions->at(i) * _domainScale + _domainOffset); + ids.push_back(particleIds->at(i)); } } } @@ -745,27 +751,35 @@ void DiffuseParticleSimulation::getFoamParticleBlurFileDataWWP(std::vector std::vector ids; translations.reserve(_diffuseParticles.size()); ids.reserve(_diffuseParticles.size()); + + std::vector *particlePositions; + std::vector *particleIds; + std::vector *particleTypes; + _diffuseParticles.getAttributeValues("POSITION", particlePositions); + _diffuseParticles.getAttributeValues("ID", particleIds); + _diffuseParticles.getAttributeValues("TYPE", particleTypes); + if (_isMeshingVolumeSet) { std::vector isSolid; - _meshingVolumeSDF->trilinearInterpolateSolidPoints(_diffuseParticles, isSolid); - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { + _meshingVolumeSDF->trilinearInterpolateSolidPoints(*particlePositions, isSolid); + for (size_t i = 0; i < _diffuseParticles.size(); i++) { if (isSolid[i]) { continue; } - if (_diffuseParticles[i].type == DiffuseParticleType::foam) { - vmath::vec3 p = _diffuseParticles[i].position; + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::foam) { + vmath::vec3 p = particlePositions->at(i); vmath::vec3 t = _vfield->evaluateVelocityAtPositionLinear(p) * _domainScale * dt; translations.push_back(t); - ids.push_back(_diffuseParticles[i].id); + ids.push_back(particleIds->at(i)); } } } else { - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { - if (_diffuseParticles[i].type == DiffuseParticleType::foam) { - vmath::vec3 p = _diffuseParticles[i].position; + for (size_t i = 0; i < _diffuseParticles.size(); i++) { + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::foam) { + vmath::vec3 p = particlePositions->at(i); vmath::vec3 t = _vfield->evaluateVelocityAtPositionLinear(p) * _domainScale * dt; translations.push_back(t); - ids.push_back(_diffuseParticles[i].id); + ids.push_back(particleIds->at(i)); } } } @@ -778,27 +792,35 @@ void DiffuseParticleSimulation::getBubbleParticleBlurFileDataWWP(std::vector ids; translations.reserve(_diffuseParticles.size()); ids.reserve(_diffuseParticles.size()); + + std::vector *particlePositions; + std::vector *particleIds; + std::vector *particleTypes; + _diffuseParticles.getAttributeValues("POSITION", particlePositions); + _diffuseParticles.getAttributeValues("ID", particleIds); + _diffuseParticles.getAttributeValues("TYPE", particleTypes); + if (_isMeshingVolumeSet) { std::vector isSolid; - _meshingVolumeSDF->trilinearInterpolateSolidPoints(_diffuseParticles, isSolid); - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { + _meshingVolumeSDF->trilinearInterpolateSolidPoints(*particlePositions, isSolid); + for (size_t i = 0; i < _diffuseParticles.size(); i++) { if (isSolid[i]) { continue; } - if (_diffuseParticles[i].type == DiffuseParticleType::bubble) { - vmath::vec3 p = _diffuseParticles[i].position; + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::bubble) { + vmath::vec3 p = particlePositions->at(i); vmath::vec3 t = _vfield->evaluateVelocityAtPositionLinear(p) * _domainScale * dt; translations.push_back(t); - ids.push_back(_diffuseParticles[i].id); + ids.push_back(particleIds->at(i)); } } } else { - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { - if (_diffuseParticles[i].type == DiffuseParticleType::bubble) { - vmath::vec3 p = _diffuseParticles[i].position; + for (size_t i = 0; i < _diffuseParticles.size(); i++) { + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::bubble) { + vmath::vec3 p = particlePositions->at(i); vmath::vec3 t = _vfield->evaluateVelocityAtPositionLinear(p) * _domainScale * dt; translations.push_back(t); - ids.push_back(_diffuseParticles[i].id); + ids.push_back(particleIds->at(i)); } } } @@ -811,27 +833,35 @@ void DiffuseParticleSimulation::getSprayParticleBlurFileDataWWP(std::vector ids; translations.reserve(_diffuseParticles.size()); ids.reserve(_diffuseParticles.size()); + + std::vector *particlePositions; + std::vector *particleIds; + std::vector *particleTypes; + _diffuseParticles.getAttributeValues("POSITION", particlePositions); + _diffuseParticles.getAttributeValues("ID", particleIds); + _diffuseParticles.getAttributeValues("TYPE", particleTypes); + if (_isMeshingVolumeSet) { std::vector isSolid; - _meshingVolumeSDF->trilinearInterpolateSolidPoints(_diffuseParticles, isSolid); - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { + _meshingVolumeSDF->trilinearInterpolateSolidPoints(*particlePositions, isSolid); + for (size_t i = 0; i < _diffuseParticles.size(); i++) { if (isSolid[i]) { continue; } - if (_diffuseParticles[i].type == DiffuseParticleType::spray) { - vmath::vec3 p = _diffuseParticles[i].position; + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::spray) { + vmath::vec3 p = particlePositions->at(i); vmath::vec3 t = _vfield->evaluateVelocityAtPositionLinear(p) * _domainScale * dt; translations.push_back(t); - ids.push_back(_diffuseParticles[i].id); + ids.push_back(particleIds->at(i)); } } } else { - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { - if (_diffuseParticles[i].type == DiffuseParticleType::spray) { - vmath::vec3 p = _diffuseParticles[i].position; + for (size_t i = 0; i < _diffuseParticles.size(); i++) { + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::spray) { + vmath::vec3 p = particlePositions->at(i); vmath::vec3 t = _vfield->evaluateVelocityAtPositionLinear(p) * _domainScale * dt; translations.push_back(t); - ids.push_back(_diffuseParticles[i].id); + ids.push_back(particleIds->at(i)); } } } @@ -844,27 +874,35 @@ void DiffuseParticleSimulation::getDustParticleBlurFileDataWWP(std::vector std::vector ids; translations.reserve(_diffuseParticles.size()); ids.reserve(_diffuseParticles.size()); + + std::vector *particlePositions; + std::vector *particleIds; + std::vector *particleTypes; + _diffuseParticles.getAttributeValues("POSITION", particlePositions); + _diffuseParticles.getAttributeValues("ID", particleIds); + _diffuseParticles.getAttributeValues("TYPE", particleTypes); + if (_isMeshingVolumeSet) { std::vector isSolid; - _meshingVolumeSDF->trilinearInterpolateSolidPoints(_diffuseParticles, isSolid); - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { + _meshingVolumeSDF->trilinearInterpolateSolidPoints(*particlePositions, isSolid); + for (size_t i = 0; i < _diffuseParticles.size(); i++) { if (isSolid[i]) { continue; } - if (_diffuseParticles[i].type == DiffuseParticleType::dust) { - vmath::vec3 p = _diffuseParticles[i].position; + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::dust) { + vmath::vec3 p = particlePositions->at(i); vmath::vec3 t = _vfield->evaluateVelocityAtPositionLinear(p) * _domainScale * dt; translations.push_back(t); - ids.push_back(_diffuseParticles[i].id); + ids.push_back(particleIds->at(i)); } } } else { - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { - if (_diffuseParticles[i].type == DiffuseParticleType::dust) { - vmath::vec3 p = _diffuseParticles[i].position; + for (size_t i = 0; i < _diffuseParticles.size(); i++) { + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::dust) { + vmath::vec3 p = particlePositions->at(i); vmath::vec3 t = _vfield->evaluateVelocityAtPositionLinear(p) * _domainScale * dt; translations.push_back(t); - ids.push_back(_diffuseParticles[i].id); + ids.push_back(particleIds->at(i)); } } } @@ -874,10 +912,18 @@ void DiffuseParticleSimulation::getDustParticleBlurFileDataWWP(std::vector void DiffuseParticleSimulation::loadDiffuseParticles(FragmentedVector &particles) { _diffuseParticles.reserve(_diffuseParticles.size() + particles.size()); + + DiffuseParticleAttributes atts = _getDiffuseParticleAttributes(); + for (size_t i = 0; i < particles.size(); i++) { DiffuseParticle dp = particles[i]; - dp.position = (dp.position - _domainOffset) / _domainScale; - _diffuseParticles.push_back(dp); + vmath::vec3 p = (dp.position - _domainOffset) / _domainScale; + + atts.positions->push_back(p); + atts.velocities->push_back(dp.velocity); + atts.lifetimes->push_back(dp.lifetime); + atts.types->push_back((char)dp.type); + atts.ids->push_back(dp.id); } } @@ -903,6 +949,16 @@ void DiffuseParticleSimulation:: _shuffleDiffuseParticleEmitters(dustEmitters); } +DiffuseParticleSimulation::DiffuseParticleAttributes DiffuseParticleSimulation::_getDiffuseParticleAttributes() { + DiffuseParticleAttributes atts; + _diffuseParticles.getAttributeValues("POSITION", atts.positions); + _diffuseParticles.getAttributeValues("VELOCITY", atts.velocities); + _diffuseParticles.getAttributeValues("LIFETIME", atts.lifetimes); + _diffuseParticles.getAttributeValues("TYPE", atts.types); + _diffuseParticles.getAttributeValues("ID", atts.ids); + return atts; +} + void DiffuseParticleSimulation::_trilinearInterpolate(std::vector &input, MACVelocityField *vfield, std::vector &output) { @@ -949,13 +1005,14 @@ void DiffuseParticleSimulation:: _sortMarkerParticlePositions(std::vector &surface, std::vector &inside) { + std::vector *positions; + _markerParticles->getAttributeValues("POSITION", positions); + double jitter = _getParticleJitter(); float width = (float)(_diffuseSurfaceNarrowBandSize * _dx); vmath::vec3 hdx(0.5*_dx, 0.5*_dx, 0.5*_dx); - vmath::vec3 p; - GridIndex g; - for (int i = 0; i < (int)_markerParticles->size(); i++) { - p = _markerParticles->at(i).position; + for (size_t i = 0; i < positions->size(); i++) { + vmath::vec3 p = positions->at(i); p = _jitterParticlePosition(p, jitter); if (!_emitterGenerationBounds.isPointInside(p)) { continue; @@ -964,7 +1021,7 @@ void DiffuseParticleSimulation:: float signedDistance = Interpolation::trilinearInterpolate(p - hdx, _dx, *_surfaceSDF); if (fabs(signedDistance) < width) { - g = Grid3d::positionToGridIndex(p, _dx); + GridIndex g = Grid3d::positionToGridIndex(p, _dx); if (!_isBorderingAirGridSet(g)) { _borderingAirGrid.set(g, _mgrid.isCellNeighbouringAir(g)); _isBorderingAirGridSet.set(g, true); @@ -1245,6 +1302,20 @@ void DiffuseParticleSimulation:: } } +void DiffuseParticleSimulation::_addNewDiffuseParticles(std::vector &newDiffuseParticles) { + DiffuseParticleAttributes atts = _getDiffuseParticleAttributes(); + for (size_t i = 0; i < newDiffuseParticles.size(); i++) { + DiffuseParticle dp = newDiffuseParticles[i]; + atts.positions->push_back(dp.position); + atts.velocities->push_back(dp.velocity); + atts.lifetimes->push_back(dp.lifetime); + atts.types->push_back((char)dp.type); + atts.ids->push_back(dp.id); + } + + _diffuseParticles.update(); +} + void DiffuseParticleSimulation::_emitNormalDiffuseParticles(std::vector &emitters, double dt) { std::vector newdps; for (size_t i = 0; i < emitters.size(); i++) { @@ -1256,12 +1327,7 @@ void DiffuseParticleSimulation::_emitNormalDiffuseParticles(std::vector &emitters, double dt) { @@ -1279,12 +1345,7 @@ void DiffuseParticleSimulation::_emitDustDiffuseParticles(std::vectorat(i) == DiffuseParticleType::dust) { continue; } - dp = _diffuseParticles[i]; - oldtype = dp.type; - newtype = _getDiffuseParticleType(dp, boundary); - _diffuseParticles[i].type = newtype; + DiffuseParticle dp = atts.getDiffuseParticle(i); + DiffuseParticleType oldtype = dp.type; + DiffuseParticleType newtype = _getDiffuseParticleType(dp, boundary); + atts.types->at(i) = (char)newtype; if (oldtype == DiffuseParticleType::bubble && (newtype == DiffuseParticleType::foam || newtype == DiffuseParticleType::spray)) { vmath::vec3 newv = _vfield->evaluateVelocityAtPositionLinear(dp.position); - _diffuseParticles[i].velocity = newv; + atts.velocities->at(i) = newv; } } } @@ -1481,23 +1541,22 @@ DiffuseParticleType DiffuseParticleSimulation::_getDiffuseParticleType(DiffusePa } void DiffuseParticleSimulation::_updateDiffuseParticleLifetimes(double dt) { - - DiffuseParticle dp; + DiffuseParticleAttributes atts = _getDiffuseParticleAttributes(); for (int i = 0; i < (int)_diffuseParticles.size(); i++) { - dp = _diffuseParticles[i]; + DiffuseParticle dp = atts.getDiffuseParticle(i); double modifier = 0.0; - if (dp.type == DiffuseParticleType::spray) { + if ((DiffuseParticleType)dp.type == DiffuseParticleType::spray) { modifier = _sprayParticleLifetimeModifier; - } else if (dp.type == DiffuseParticleType::bubble) { + } else if ((DiffuseParticleType)dp.type == DiffuseParticleType::bubble) { modifier = _bubbleParticleLifetimeModifier; - } else if (dp.type == DiffuseParticleType::foam) { + } else if ((DiffuseParticleType)dp.type == DiffuseParticleType::foam) { modifier = _foamParticleLifetimeModifier; - } else if (dp.type == DiffuseParticleType::dust) { + } else if ((DiffuseParticleType)dp.type == DiffuseParticleType::dust) { modifier = _dustParticleLifetimeModifier; } - _diffuseParticles[i].lifetime = dp.lifetime - (float)(modifier * dt); + atts.lifetimes->at(i) = dp.lifetime - (float)(modifier * dt); } _updateFoamPreservation(dt); @@ -1508,22 +1567,26 @@ void DiffuseParticleSimulation::_updateFoamPreservation(double dt) { return; } + DiffuseParticleAttributes atts = _getDiffuseParticleAttributes(); + Array3d densityGrid(_isize, _jsize, _ksize, 0); - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { - if (_diffuseParticles[i].type == DiffuseParticleType::foam) { - GridIndex g = Grid3d::positionToGridIndex(_diffuseParticles[i].position, _dx); + for (size_t i = 0; i < _diffuseParticles.size(); i++) { + DiffuseParticle dp = atts.getDiffuseParticle(i); + if (dp.type == DiffuseParticleType::foam) { + GridIndex g = Grid3d::positionToGridIndex(dp.position, _dx); densityGrid.add(g, 1); } } double invdiff = 1.0 / fmax(_maxFoamDensity - _minFoamDensity, 1e-6); - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { - if (_diffuseParticles[i].type == DiffuseParticleType::foam) { - GridIndex g = Grid3d::positionToGridIndex(_diffuseParticles[i].position, _dx); + for (size_t i = 0; i < _diffuseParticles.size(); i++) { + DiffuseParticle dp = atts.getDiffuseParticle(i); + if (dp.type == DiffuseParticleType::foam) { + GridIndex g = Grid3d::positionToGridIndex(dp.position, _dx); double d = ((double)densityGrid(g) - _minFoamDensity) * invdiff; d = fmax(d, 0.0); d = fmin(d, 1.0); - _diffuseParticles[i].lifetime += _foamPreservationRate * d * dt; + atts.lifetimes->at(i) = dp.lifetime + _foamPreservationRate * d * dt; } } } @@ -1630,10 +1693,12 @@ void DiffuseParticleSimulation::_advanceSprayParticlesThread(int startidx, int e AABB boundary = _getBoundaryAABB(); boundary.expand(-_solidBufferWidth * _dx); + DiffuseParticleAttributes atts = _getDiffuseParticleAttributes(); + + float deadParticleLifetime = -1e6; float invdt = 1.0f / (float)dt; for (int i = startidx; i < endidx; i++) { - DiffuseParticle dp = _diffuseParticles[i]; - + DiffuseParticle dp = atts.getDiffuseParticle(i); if (dp.type != DiffuseParticleType::spray) { continue; } @@ -1651,11 +1716,11 @@ void DiffuseParticleSimulation::_advanceSprayParticlesThread(int startidx, int e float maxv = (float)_maxVelocityFactor * vmath::length(nextv); if (vmath::length(nextp - dp.position) * invdt > maxv) { - _markParticleForRemoval(i); + atts.lifetimes->at(i) = deadParticleLifetime; } - _diffuseParticles[i].position = nextp; - _diffuseParticles[i].velocity = nextv; + atts.positions->at(i) = nextp; + atts.velocities->at(i) = nextv; } } @@ -1663,9 +1728,12 @@ void DiffuseParticleSimulation::_advanceBubbleParticlesThread(int startidx, int AABB boundary = _getBoundaryAABB(); boundary.expand(-_solidBufferWidth * _dx); + DiffuseParticleAttributes atts = _getDiffuseParticleAttributes(); + + float deadParticleLifetime = -1e6; float invdt = 1.0f / (float)dt; for (int i = startidx; i < endidx; i++) { - DiffuseParticle dp = _diffuseParticles[i]; + DiffuseParticle dp = atts.getDiffuseParticle(i); if (dp.type != DiffuseParticleType::bubble) { continue; } @@ -1682,11 +1750,11 @@ void DiffuseParticleSimulation::_advanceBubbleParticlesThread(int startidx, int float maxv = (float)_maxVelocityFactor * vmath::length(nextv); if (vmath::length(nextp - dp.position) * invdt > maxv) { - _markParticleForRemoval(i); + atts.lifetimes->at(i) = deadParticleLifetime; } - _diffuseParticles[i].position = nextp; - _diffuseParticles[i].velocity = nextv; + atts.positions->at(i) = nextp; + atts.velocities->at(i) = nextv; } } @@ -1694,9 +1762,12 @@ void DiffuseParticleSimulation::_advanceFoamParticlesThread(int startidx, int en AABB boundary = _getBoundaryAABB(); boundary.expand(-_solidBufferWidth * _dx); + DiffuseParticleAttributes atts = _getDiffuseParticleAttributes(); + + float deadParticleLifetime = -1e6; float invdt = 1.0f / (float)dt; for (int i = startidx; i < endidx; i++) { - DiffuseParticle dp = _diffuseParticles[i]; + DiffuseParticle dp = atts.getDiffuseParticle(i); if (dp.type != DiffuseParticleType::foam) { continue; } @@ -1708,11 +1779,11 @@ void DiffuseParticleSimulation::_advanceFoamParticlesThread(int startidx, int en float maxv = (float)_maxVelocityFactor * vmath::length(nextv); if (vmath::length(nextp - dp.position) * invdt > maxv) { - _markParticleForRemoval(i); + atts.lifetimes->at(i) = deadParticleLifetime; } - _diffuseParticles[i].position = nextp; - _diffuseParticles[i].velocity = nextv; + atts.positions->at(i) = nextp; + atts.velocities->at(i) = nextv; } } @@ -1720,9 +1791,12 @@ void DiffuseParticleSimulation::_advanceDustParticlesThread(int startidx, int en AABB boundary = _getBoundaryAABB(); boundary.expand(-_solidBufferWidth * _dx); + DiffuseParticleAttributes atts = _getDiffuseParticleAttributes(); + + float deadParticleLifetime = -1e6; float invdt = 1.0f / (float)dt; for (int i = startidx; i < endidx; i++) { - DiffuseParticle dp = _diffuseParticles[i]; + DiffuseParticle dp = atts.getDiffuseParticle(i); if (dp.type != DiffuseParticleType::dust) { continue; } @@ -1748,11 +1822,11 @@ void DiffuseParticleSimulation::_advanceDustParticlesThread(int startidx, int en float maxv = (float)_maxVelocityFactor * vmath::length(nextv); if (vmath::length(nextp - dp.position) * invdt > maxv) { - _markParticleForRemoval(i); + atts.lifetimes->at(i) = deadParticleLifetime; } - _diffuseParticles[i].position = nextp; - _diffuseParticles[i].velocity = nextv; + atts.positions->at(i) = nextp; + atts.velocities->at(i) = nextv; } } @@ -1903,10 +1977,6 @@ int DiffuseParticleSimulation::_getNearestSideIndex(vmath::vec3 p, AABB &boundar return 0; } -void DiffuseParticleSimulation::_markParticleForRemoval(unsigned int index) { - _diffuseParticles[index].lifetime = -1e6; -} - vmath::vec3 DiffuseParticleSimulation::_getGravityVector(vmath::vec3 pos) { if (_isForceFieldGridSet) { return _forceFieldGrid->evaluateForceAtPosition(pos); @@ -1918,12 +1988,15 @@ vmath::vec3 DiffuseParticleSimulation::_getGravityVector(vmath::vec3 pos) { void DiffuseParticleSimulation:: _getDiffuseParticleTypeCounts(int *numfoam, int *numbubble, int *numspray, int *numdust) { + std::vector *particleTypes; + _diffuseParticles.getAttributeValues("TYPE", particleTypes); + int foam = 0; int bubble = 0; int spray = 0; int dust = 0; - for (unsigned int i = 0; i < _diffuseParticles.size(); i++) { - DiffuseParticleType type = _diffuseParticles[i].type; + for (size_t i = 0; i < particleTypes->size(); i++) { + DiffuseParticleType type = (DiffuseParticleType)(particleTypes->at(i)); if (type == DiffuseParticleType::foam) { foam++; } else if (type == DiffuseParticleType::bubble) { @@ -1942,9 +2015,12 @@ void DiffuseParticleSimulation:: } int DiffuseParticleSimulation::_getNumSprayParticles() { + std::vector *particleTypes; + _diffuseParticles.getAttributeValues("TYPE", particleTypes); + int spraycount = 0; - for (unsigned int i = 0; i < _diffuseParticles.size(); i++) { - if (_diffuseParticles[i].type == DiffuseParticleType::spray) { + for (unsigned int i = 0; i < particleTypes->size(); i++) { + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::spray) { spraycount++; } } @@ -1953,9 +2029,12 @@ int DiffuseParticleSimulation::_getNumSprayParticles() { } int DiffuseParticleSimulation::_getNumBubbleParticles() { + std::vector *particleTypes; + _diffuseParticles.getAttributeValues("TYPE", particleTypes); + int bubblecount = 0; - for (unsigned int i = 0; i < _diffuseParticles.size(); i++) { - if (_diffuseParticles[i].type == DiffuseParticleType::bubble) { + for (unsigned int i = 0; i < particleTypes->size(); i++) { + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::bubble) { bubblecount++; } } @@ -1964,9 +2043,12 @@ int DiffuseParticleSimulation::_getNumBubbleParticles() { } int DiffuseParticleSimulation::_getNumFoamParticles() { + std::vector *particleTypes; + _diffuseParticles.getAttributeValues("TYPE", particleTypes); + int foamcount = 0; - for (unsigned int i = 0; i < _diffuseParticles.size(); i++) { - if (_diffuseParticles[i].type == DiffuseParticleType::foam) { + for (unsigned int i = 0; i < particleTypes->size(); i++) { + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::foam) { foamcount++; } } @@ -1975,9 +2057,12 @@ int DiffuseParticleSimulation::_getNumFoamParticles() { } int DiffuseParticleSimulation::_getNumDustParticles() { + std::vector *particleTypes; + _diffuseParticles.getAttributeValues("TYPE", particleTypes); + int dustcount = 0; - for (unsigned int i = 0; i < _diffuseParticles.size(); i++) { - if (_diffuseParticles[i].type == DiffuseParticleType::dust) { + for (unsigned int i = 0; i < particleTypes->size(); i++) { + if ((DiffuseParticleType)particleTypes->at(i) == DiffuseParticleType::dust) { dustcount++; } } @@ -1990,13 +2075,15 @@ void DiffuseParticleSimulation::_removeDiffuseParticles() { AABB boundary = _getBoundaryAABB(); boundary.expand(-_solidBufferWidth * _dx); + DiffuseParticleAttributes atts = _getDiffuseParticleAttributes(); + std::vector isInsideSolid; - _solidSDF->trilinearInterpolateSolidPoints(_diffuseParticles, isInsideSolid); + _solidSDF->trilinearInterpolateSolidPoints(*(atts.positions), isInsideSolid); Array3d countGrid = Array3d(_isize, _jsize, _ksize, 0); std::vector isRemoved(_diffuseParticles.size(), false); - for (int i = 0; i < (int)_diffuseParticles.size(); i++) { - DiffuseParticle dp = _diffuseParticles[i]; + for (size_t i = 0; i < _diffuseParticles.size(); i++) { + DiffuseParticle dp = atts.getDiffuseParticle(i); if ((!_isFoamEnabled && dp.type == DiffuseParticleType::foam) || (!_isBubblesEnabled && dp.type == DiffuseParticleType::bubble) || (!_isSprayEnabled && dp.type == DiffuseParticleType::spray) || @@ -2037,13 +2124,10 @@ void DiffuseParticleSimulation::_removeDiffuseParticles() { } } - _removeItemsFromVector(_diffuseParticles, isRemoved); + _diffuseParticles.removeParticles(isRemoved); if (_diffuseParticles.size() >= _maxNumDiffuseParticles) { - int n = _diffuseParticles.size() - _maxNumDiffuseParticles; - for (int i = 0; i < n; i++) { - _diffuseParticles.pop_back(); - } + _diffuseParticles.resize(_maxNumDiffuseParticles); } } diff --git a/src/engine/diffuseparticlesimulation.h b/src/engine/diffuseparticlesimulation.h index e1cf03b4..086692d3 100644 --- a/src/engine/diffuseparticlesimulation.h +++ b/src/engine/diffuseparticlesimulation.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -37,9 +37,10 @@ SOFTWARE. #include "aabb.h" #include "fluidmaterialgrid.h" #include "turbulencefield.h" +#include "particlesystem.h" +#include "diffuseparticle.h" struct MarkerParticle; -struct DiffuseParticle; enum class DiffuseParticleType : char; class MeshLevelSet; class MACVelocityField; @@ -57,7 +58,7 @@ struct DiffuseParticleSimulationParameters { double markerParticleRadius; vmath::vec3 bodyForce; - FragmentedVector *markerParticles; + ParticleSystem *markerParticles; MACVelocityField *vfield; ParticleLevelSet *liquidSDF; MeshLevelSet *solidSDF; @@ -120,12 +121,8 @@ class DiffuseParticleSimulation void disableBoundaryDustEmission(); bool isBoundaryDustEmissionEnabled(); - FragmentedVector* getDiffuseParticles(); + ParticleSystem* getDiffuseParticles(); int getNumDiffuseParticles(); - void setDiffuseParticles(std::vector &particles); - void setDiffuseParticles(FragmentedVector &particles); - void addDiffuseParticles(std::vector &particles); - void addDiffuseParticles(FragmentedVector &particles); double getEmitterGenerationRate(); void setEmitterGenerationRate(double rate); @@ -271,6 +268,26 @@ class DiffuseParticleSimulation dustPotential(d) {} }; + struct DiffuseParticleAttributes { + std::vector *positions = nullptr; + std::vector *velocities = nullptr; + std::vector *lifetimes = nullptr; + std::vector *types = nullptr; + std::vector *ids = nullptr; + + DiffuseParticle getDiffuseParticle(size_t index) { + DiffuseParticle dp; + dp.position = positions->at(index); + dp.velocity = velocities->at(index); + dp.lifetime = lifetimes->at(index); + dp.type = (DiffuseParticleType)types->at(index); + dp.id = ids->at(index); + return dp; + } + }; + + DiffuseParticleAttributes _getDiffuseParticleAttributes(); + void _trilinearInterpolate(std::vector &input, MACVelocityField *vfield, std::vector &output); void _trilinearInterpolateThread(int startidx, int endidx, @@ -298,6 +315,7 @@ class DiffuseParticleSimulation std::vector &dustEmitters); void _shuffleDiffuseParticleEmitters(std::vector &emitters); + void _addNewDiffuseParticles(std::vector &newDiffuseParticles); void _emitNormalDiffuseParticles(std::vector &emitters, double dt); void _emitDustDiffuseParticles(std::vector &emitters, double dt); void _emitDiffuseParticles(DiffuseParticleEmitter &emitter, @@ -329,7 +347,6 @@ class DiffuseParticleSimulation LimitBehaviour _getLimitBehaviour(DiffuseParticle &dp); std::vector* _getActiveSides(DiffuseParticle &dp); int _getNearestSideIndex(vmath::vec3 p, AABB &boundary); - void _markParticleForRemoval(unsigned int index); vmath::vec3 _getGravityVector(vmath::vec3 pos); @@ -445,7 +462,7 @@ class DiffuseParticleSimulation std::vector _dustActiveSides; AABB _emitterGenerationBounds; - FragmentedVector *_markerParticles; + ParticleSystem *_markerParticles; MACVelocityField *_vfield; ParticleLevelSet *_liquidSDF; MeshLevelSet *_solidSDF; @@ -463,7 +480,7 @@ class DiffuseParticleSimulation Array3d _borderingAirGrid; Array3d _isBorderingAirGridSet; TurbulenceField _turbulenceField; - FragmentedVector _diffuseParticles; + ParticleSystem _diffuseParticles; int _currentDiffuseParticleID = 0; int _diffuseParticleIDLimit = 256; diff --git a/src/engine/fluidmaterialgrid.cpp b/src/engine/fluidmaterialgrid.cpp index af35ee4b..d470fc6a 100644 --- a/src/engine/fluidmaterialgrid.cpp +++ b/src/engine/fluidmaterialgrid.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/fluidmaterialgrid.h b/src/engine/fluidmaterialgrid.h index 43a83741..a0829a03 100644 --- a/src/engine/fluidmaterialgrid.h +++ b/src/engine/fluidmaterialgrid.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/fluidsimassert.h b/src/engine/fluidsimassert.h index e025d20c..4b6b6791 100644 --- a/src/engine/fluidsimassert.h +++ b/src/engine/fluidsimassert.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/fluidsimulation.cpp b/src/engine/fluidsimulation.cpp index 8ff60a5e..51c134db 100644 --- a/src/engine/fluidsimulation.cpp +++ b/src/engine/fluidsimulation.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -34,7 +34,6 @@ SOFTWARE. #include "particlemesher.h" #include "polygonizer3d.h" #include "diffuseparticle.h" -#include "markerparticle.h" #include "particlemaskgrid.h" #include "triangle.h" #include "scalarfield.h" @@ -1669,6 +1668,23 @@ void FluidSimulation::setViscosity(double v) { _constantViscosityValue = v; } +double FluidSimulation::getViscositySolverErrorTolerance() { + return _viscositySolverErrorTolerance; +} + +void FluidSimulation::setViscositySolverErrorTolerance(double tol) { + if (tol < 0.0) { + std::string msg = "Error: viscosity solver error tolerance must be greater than or equal to 0.\n"; + msg += "error tolerance: " + _toString(tol) + "\n"; + throw std::domain_error(msg); + } + + _logfile.log(std::ostringstream().flush() << + _logfile.getTime() << " setViscositySolverErrorTolerance: " << tol << std::endl); + + _viscositySolverErrorTolerance = tol; +} + double FluidSimulation::getSurfaceTension() { return _surfaceTensionConstant; } @@ -1884,6 +1900,28 @@ bool FluidSimulation::isExtremeVelocityRemovalEnabled() { return _isExtremeVelocityRemovalEnabled; } +void FluidSimulation::setVelocityTransferMethodFLIP() { + _logfile.log(std::ostringstream().flush() << + _logfile.getTime() << " setVelocityTransferMethodFLIP" << std::endl); + + _velocityTransferMethod = VelocityTransferMethod::FLIP; +} + +void FluidSimulation::setVelocityTransferMethodAPIC() { + _logfile.log(std::ostringstream().flush() << + _logfile.getTime() << " setVelocityTransferMethodAPIC" << std::endl); + + _velocityTransferMethod = VelocityTransferMethod::APIC; +} + +bool FluidSimulation::isVelocityTransferMethodFLIP() { + return _velocityTransferMethod == VelocityTransferMethod::FLIP; +} + +bool FluidSimulation::isVelocityTransferMethodAPIC() { + return _velocityTransferMethod == VelocityTransferMethod::APIC; +} + double FluidSimulation::getPICFLIPRatio() { return _ratioPICFLIP; } @@ -1902,6 +1940,24 @@ void FluidSimulation::setPICFLIPRatio(double r) { _ratioPICFLIP = r; } +double FluidSimulation::getPICAPICRatio() { + return _ratioPICAPIC; +} + +void FluidSimulation::setPICAPICRatio(double r) { + if (r < 0.0 || r > 1.0) { + std::string msg = "Error: PICAPIC ratio must be in range [0.0, 1.0].\n"; + msg += "ratio: " + _toString(r) + "\n"; + throw std::domain_error(msg); + } + + _logfile.log(std::ostringstream().flush() << + _logfile.getTime() << + " setPICAPICRatio: " << r << std::endl); + + _ratioPICAPIC = r; +} + void FluidSimulation::setPreferredGPUDevice(std::string deviceName) { _logfile.log(std::ostringstream().flush() << _logfile.getTime() << @@ -2065,8 +2121,13 @@ std::vector FluidSimulation::getMarkerParticles(int startidx, in std::vector particles; particles.reserve(endidx - startidx); + std::vector *positions, *velocities; + _markerParticles.getAttributeValues("POSITION", positions); + _markerParticles.getAttributeValues("VELOCITY", velocities); + for (int i = startidx; i < endidx; i++) { - particles.push_back(_markerParticles[i]); + MarkerParticle mp(positions->at(i), velocities->at(i)); + particles.push_back(mp); } return particles; @@ -2087,8 +2148,11 @@ std::vector FluidSimulation::getMarkerParticlePositions(int startid std::vector particles; particles.reserve(endidx - startidx); + std::vector *positions; + _markerParticles.getAttributeValues("POSITION", positions); + for (int i = startidx; i < endidx; i++) { - particles.push_back(_markerParticles[i].position); + particles.push_back(positions->at(i)); } return particles; @@ -2109,8 +2173,11 @@ std::vector FluidSimulation::getMarkerParticleVelocities(int starti std::vector velocities; velocities.reserve(endidx - startidx); + std::vector *values; + _markerParticles.getAttributeValues("VELOCITY", values); + for (int i = startidx; i < endidx; i++) { - velocities.push_back(_markerParticles[i].velocity); + velocities.push_back(values->at(i)); } return velocities; @@ -2120,29 +2187,6 @@ unsigned int FluidSimulation::getNumDiffuseParticles() { return _diffuseMaterial.getNumDiffuseParticles(); } -std::vector FluidSimulation::getDiffuseParticles() { - return getDiffuseParticles(0, _markerParticles.size()); -} - -std::vector FluidSimulation::getDiffuseParticles(int startidx, int endidx) { - int size = getNumDiffuseParticles(); - if (!(startidx >= 0 && startidx <= size) || !(endidx >= 0 && endidx <= size)) { - std::string msg = "Error: invalid index range.\n"; - msg += "start index: " + _toString(startidx) + " end index: " + _toString(endidx) + "\n"; - throw std::out_of_range(msg); - } - - std::vector particles; - particles.reserve(endidx - startidx); - - FragmentedVector *dps = _diffuseMaterial.getDiffuseParticles(); - for (int i = startidx; i < endidx; i++) { - particles.push_back(dps->at(i)); - } - - return particles; -} - std::vector FluidSimulation::getDiffuseParticlePositions() { int size = getNumDiffuseParticles(); return getDiffuseParticlePositions(0, size); @@ -2156,15 +2200,11 @@ std::vector FluidSimulation::getDiffuseParticlePositions(int starti throw std::out_of_range(msg); } - std::vector particles; - particles.reserve(endidx - startidx); - - FragmentedVector *dps = _diffuseMaterial.getDiffuseParticles(); - for (int i = startidx; i < endidx; i++) { - particles.push_back(dps->at(i).position); - } + std::vector *positions; + ParticleSystem *dps = _diffuseMaterial.getDiffuseParticles(); + dps->getAttributeValues("POSITION", positions); - return particles; + return *positions; } std::vector FluidSimulation::getDiffuseParticleVelocities() { @@ -2180,15 +2220,11 @@ std::vector FluidSimulation::getDiffuseParticleVelocities(int start throw std::out_of_range(msg); } - std::vector velocities; - velocities.reserve(endidx - startidx); - - FragmentedVector *dps = _diffuseMaterial.getDiffuseParticles(); - for (int i = startidx; i < endidx; i++) { - velocities.push_back(dps->at(i).velocity); - } - - return velocities; + std::vector *velocities; + ParticleSystem *dps = _diffuseMaterial.getDiffuseParticles(); + dps->getAttributeValues("VELOCITY", velocities); + + return *velocities; } std::vector FluidSimulation::getDiffuseParticleLifetimes() { @@ -2204,15 +2240,11 @@ std::vector FluidSimulation::getDiffuseParticleLifetimes(int startidx, in throw std::out_of_range(msg); } - std::vector lifetimes; - lifetimes.reserve(endidx - startidx); - - FragmentedVector *dps = _diffuseMaterial.getDiffuseParticles(); - for (int i = startidx; i < endidx; i++) { - lifetimes.push_back(dps->at(i).lifetime); - } - - return lifetimes; + std::vector *lifetimes; + ParticleSystem *dps = _diffuseMaterial.getDiffuseParticles(); + dps->getAttributeValues("LIFETIME", lifetimes); + + return *lifetimes; } std::vector FluidSimulation::getDiffuseParticleTypes() { @@ -2228,15 +2260,11 @@ std::vector FluidSimulation::getDiffuseParticleTypes(int startidx, int end throw std::out_of_range(msg); } - std::vector types; - types.reserve(endidx - startidx); - - FragmentedVector *dps = _diffuseMaterial.getDiffuseParticles(); - for (int i = startidx; i < endidx; i++) { - types.push_back((char)(dps->at(i).type)); - } - - return types; + std::vector *types; + ParticleSystem *dps = _diffuseMaterial.getDiffuseParticles(); + dps->getAttributeValues("TYPE", types); + + return *types; } MACVelocityField* FluidSimulation::getVelocityField() { @@ -2318,9 +2346,12 @@ void FluidSimulation::getMarkerParticlePositionDataRange(int start_idx, int end_ throw std::domain_error(msg); } + std::vector *values; + _markerParticles.getAttributeValues("POSITION", values); + vmath::vec3 *positions = (vmath::vec3*)data; for (int i = start_idx; i < end_idx; i++) { - positions[i - start_idx] = _markerParticles[i].position * _domainScale + _domainOffset; + positions[i - start_idx] = values->at(i) * _domainScale + _domainOffset; } } @@ -2331,129 +2362,216 @@ void FluidSimulation::getMarkerParticleVelocityDataRange(int start_idx, int end_ throw std::domain_error(msg); } + std::vector *values; + _markerParticles.getAttributeValues("VELOCITY", values); + vmath::vec3 *velocities = (vmath::vec3*)data; for (int i = start_idx; i < end_idx; i++) { - velocities[i - start_idx] = _markerParticles[i].velocity; + velocities[i - start_idx] = values->at(i); + } +} + +void FluidSimulation::getMarkerParticleAffineXDataRange(int start_idx, int end_idx, char *data) { + if (start_idx < 0 || end_idx > (int)_markerParticles.size() || start_idx > end_idx) { + std::string msg = "Error: invalid range.\n"; + msg += "range: [" + _toString(start_idx) + ", " + _toString(end_idx) + "]\n"; + throw std::domain_error(msg); + } + + std::vector *values; + _markerParticles.getAttributeValues("AFFINEX", values); + + vmath::vec3 *dataValues = (vmath::vec3*)data; + for (int i = start_idx; i < end_idx; i++) { + dataValues[i - start_idx] = values->at(i); + } +} + +void FluidSimulation::getMarkerParticleAffineYDataRange(int start_idx, int end_idx, char *data) { + if (start_idx < 0 || end_idx > (int)_markerParticles.size() || start_idx > end_idx) { + std::string msg = "Error: invalid range.\n"; + msg += "range: [" + _toString(start_idx) + ", " + _toString(end_idx) + "]\n"; + throw std::domain_error(msg); + } + + std::vector *values; + _markerParticles.getAttributeValues("AFFINEY", values); + + vmath::vec3 *dataValues = (vmath::vec3*)data; + for (int i = start_idx; i < end_idx; i++) { + dataValues[i - start_idx] = values->at(i); + } +} + +void FluidSimulation::getMarkerParticleAffineZDataRange(int start_idx, int end_idx, char *data) { + if (start_idx < 0 || end_idx > (int)_markerParticles.size() || start_idx > end_idx) { + std::string msg = "Error: invalid range.\n"; + msg += "range: [" + _toString(start_idx) + ", " + _toString(end_idx) + "]\n"; + throw std::domain_error(msg); + } + + std::vector *values; + _markerParticles.getAttributeValues("AFFINEZ", values); + + vmath::vec3 *dataValues = (vmath::vec3*)data; + for (int i = start_idx; i < end_idx; i++) { + dataValues[i - start_idx] = values->at(i); } } void FluidSimulation::getDiffuseParticlePositionDataRange(int start_idx, int end_idx, char *data) { - FragmentedVector* dps = _diffuseMaterial.getDiffuseParticles(); + ParticleSystem *dps = _diffuseMaterial.getDiffuseParticles(); if (start_idx < 0 || end_idx > (int)dps->size() || start_idx > end_idx) { std::string msg = "Error: invalid range.\n"; msg += "range: [" + _toString(start_idx) + ", " + _toString(end_idx) + "]\n"; throw std::domain_error(msg); } + std::vector *particlePositions; + dps->getAttributeValues("POSITION", particlePositions); + vmath::vec3 *positions = (vmath::vec3*)data; for (int i = start_idx; i < end_idx; i++) { - positions[i - start_idx] = dps->at(i).position * _domainScale + _domainOffset; + positions[i - start_idx] = particlePositions->at(i) * _domainScale + _domainOffset; } } void FluidSimulation::getDiffuseParticleVelocityDataRange(int start_idx, int end_idx, char *data) { - FragmentedVector* dps = _diffuseMaterial.getDiffuseParticles(); + ParticleSystem *dps = _diffuseMaterial.getDiffuseParticles(); if (start_idx < 0 || end_idx > (int)dps->size() || start_idx > end_idx) { std::string msg = "Error: invalid range.\n"; msg += "range: [" + _toString(start_idx) + ", " + _toString(end_idx) + "]\n"; throw std::domain_error(msg); } + std::vector *particleVelocities; + dps->getAttributeValues("VELOCITY", particleVelocities); + vmath::vec3 *velocities = (vmath::vec3*)data; for (int i = start_idx; i < end_idx; i++) { - velocities[i - start_idx] = dps->at(i).velocity; + velocities[i - start_idx] = particleVelocities->at(i); } } void FluidSimulation::getDiffuseParticleLifetimeDataRange(int start_idx, int end_idx, char *data) { - FragmentedVector* dps = _diffuseMaterial.getDiffuseParticles(); + ParticleSystem *dps = _diffuseMaterial.getDiffuseParticles(); if (start_idx < 0 || end_idx > (int)dps->size() || start_idx > end_idx) { std::string msg = "Error: invalid range.\n"; msg += "range: [" + _toString(start_idx) + ", " + _toString(end_idx) + "]\n"; throw std::domain_error(msg); } + std::vector *particleLifetimes; + dps->getAttributeValues("LIFETIME", particleLifetimes); + float *lifetimes = (float*)data; for (int i = start_idx; i < end_idx; i++) { - lifetimes[i - start_idx] = dps->at(i).lifetime; + lifetimes[i - start_idx] = particleLifetimes->at(i); } } void FluidSimulation::getDiffuseParticleTypeDataRange(int start_idx, int end_idx, char *data) { - FragmentedVector* dps = _diffuseMaterial.getDiffuseParticles(); + ParticleSystem *dps = _diffuseMaterial.getDiffuseParticles(); if (start_idx < 0 || end_idx > (int)dps->size() || start_idx > end_idx) { std::string msg = "Error: invalid range.\n"; msg += "range: [" + _toString(start_idx) + ", " + _toString(end_idx) + "]\n"; throw std::domain_error(msg); } + std::vector *particleTypes; + dps->getAttributeValues("TYPE", particleTypes); + for (int i = start_idx; i < end_idx; i++) { - data[i - start_idx] = (char)(dps->at(i).type); + data[i - start_idx] = particleTypes->at(i); } } void FluidSimulation::getDiffuseParticleIdDataRange(int start_idx, int end_idx, char *data) { - FragmentedVector* dps = _diffuseMaterial.getDiffuseParticles(); + ParticleSystem *dps = _diffuseMaterial.getDiffuseParticles(); if (start_idx < 0 || end_idx > (int)dps->size() || start_idx > end_idx) { std::string msg = "Error: invalid range.\n"; msg += "range: [" + _toString(start_idx) + ", " + _toString(end_idx) + "]\n"; throw std::domain_error(msg); } + std::vector *particleIds; + dps->getAttributeValues("TYPE", particleIds); + for (int i = start_idx; i < end_idx; i++) { - data[i - start_idx] = (char)(dps->at(i).id); + data[i - start_idx] = (char)(particleIds->at(i)); } } void FluidSimulation::getMarkerParticlePositionData(char *data) { + std::vector *values; + _markerParticles.getAttributeValues("POSITION", values); + vmath::vec3 *positions = (vmath::vec3*)data; for (size_t i = 0; i < _markerParticles.size(); i++) { - positions[i] = _markerParticles[i].position * _domainScale + _domainOffset; + positions[i] = values->at(i) * _domainScale + _domainOffset; } } void FluidSimulation::getMarkerParticleVelocityData(char *data) { + std::vector *values; + _markerParticles.getAttributeValues("POSITION", values); + vmath::vec3 *velocities = (vmath::vec3*)data; for (size_t i = 0; i < _markerParticles.size(); i++) { - velocities[i] = _markerParticles[i].velocity; + velocities[i] = values->at(i); } } void FluidSimulation::getDiffuseParticlePositionData(char *data) { - FragmentedVector* dps = _diffuseMaterial.getDiffuseParticles(); + std::vector *particlePositions; + ParticleSystem* dps = _diffuseMaterial.getDiffuseParticles(); + dps->getAttributeValues("POSITION", particlePositions); + vmath::vec3 *positions = (vmath::vec3*)data; for (size_t i = 0; i < dps->size(); i++) { - positions[i] = dps->at(i).position * _domainScale + _domainOffset; + positions[i] = particlePositions->at(i) * _domainScale + _domainOffset; } } void FluidSimulation::getDiffuseParticleVelocityData(char *data) { - FragmentedVector* dps = _diffuseMaterial.getDiffuseParticles(); + std::vector *particleVelocities; + ParticleSystem* dps = _diffuseMaterial.getDiffuseParticles(); + dps->getAttributeValues("VELOCITY", particleVelocities); + vmath::vec3 *velocities = (vmath::vec3*)data; for (size_t i = 0; i < dps->size(); i++) { - velocities[i] = dps->at(i).velocity; + velocities[i] = particleVelocities->at(i); } } void FluidSimulation::getDiffuseParticleLifetimeData(char *data) { - FragmentedVector* dps = _diffuseMaterial.getDiffuseParticles(); + std::vector *particleLifetimes; + ParticleSystem* dps = _diffuseMaterial.getDiffuseParticles(); + dps->getAttributeValues("LIFETIME", particleLifetimes); + float *lifetimes = (float*)data; for (size_t i = 0; i < dps->size(); i++) { - lifetimes[i] = dps->at(i).lifetime; + lifetimes[i] = particleLifetimes->at(i); } } void FluidSimulation::getDiffuseParticleTypeData(char *data) { - FragmentedVector* dps = _diffuseMaterial.getDiffuseParticles(); + std::vector *particleTypes; + ParticleSystem* dps = _diffuseMaterial.getDiffuseParticles(); + dps->getAttributeValues("TYPE", particleTypes); + for (size_t i = 0; i < dps->size(); i++) { - data[i] = (char)(dps->at(i).type); + data[i] = particleTypes->at(i); } } void FluidSimulation::getDiffuseParticleIdData(char *data) { - FragmentedVector* dps = _diffuseMaterial.getDiffuseParticles(); + std::vector *particleIds; + ParticleSystem* dps = _diffuseMaterial.getDiffuseParticles(); + dps->getAttributeValues("TYPE", particleIds); + for (size_t i = 0; i < dps->size(); i++) { - data[i] = (char)(dps->at(i).id); + data[i] = (char)(particleIds->at(i)); } } @@ -2508,6 +2626,30 @@ void FluidSimulation::loadMarkerParticleData(FluidSimulationMarkerParticleData d _isMarkerParticleLoadPending = true; } +void FluidSimulation::loadMarkerParticleAffineData(FluidSimulationMarkerParticleAffineData data) { + _logfile.log(std::ostringstream().flush() << + _logfile.getTime() << " loadMarkerParticleAffineData: " << data.size << std::endl); + + if (data.size == 0) { + return; + } + + vmath::vec3 *affineX = (vmath::vec3*)(data.affineX); + vmath::vec3 *affineY = (vmath::vec3*)(data.affineY); + vmath::vec3 *affineZ = (vmath::vec3*)(data.affineZ); + + MarkerParticleAffineLoadData loadData; + loadData.particles.reserve(data.size); + + for (unsigned int i = 0; i < (unsigned int)data.size; i++) { + loadData.particles.push_back(MarkerParticleAffine(affineX[i], affineY[i], affineZ[i])); + } + + _markerParticleAffineLoadQueue.push_back(loadData); + + _isMarkerParticleLoadPending = true; +} + void FluidSimulation::loadDiffuseParticleData(FluidSimulationDiffuseParticleData data) { _logfile.log(std::ostringstream().flush() << _logfile.getTime() << " loadDiffuseParticleData: " << data.size << std::endl); @@ -2615,6 +2757,17 @@ void FluidSimulation::_initializeSimulationGrids(int isize, int jsize, int ksize _triz = std::vector({1, 47, 0, 1, 46, 47, 2, 46, 1, 2, 45, 46, 3, 45, 2, 3, 44, 45, 4, 44, 3, 4, 43, 44, 5, 43, 4, 5, 42, 43, 6, 42, 5, 6, 41, 42, 7, 48, 6, 48, 41, 6, 7, 95, 48, 49, 41, 48, 7, 94, 95, 50, 41, 49, 7, 93, 94, 51, 41, 50, 51, 40, 41, 8, 93, 7, 8, 92, 93, 52, 40, 51, 8, 91, 92, 53, 40, 52, 8, 90, 91, 54, 40, 53, 54, 39, 40, 9, 90, 8, 9, 89, 90, 55, 39, 54, 9, 88, 89, 56, 39, 55, 56, 38, 39, 10, 88, 9, 10, 87, 88, 57, 38, 56, 57, 37, 38, 11, 87, 10, 11, 86, 87, 58, 37, 57, 11, 85, 86, 59, 37, 58, 59, 36, 37, 12, 85, 11, 12, 84, 85, 60, 36, 59, 13, 84, 12, 13, 83, 84, 60, 35, 36, 61, 35, 60, 13, 82, 83, 62, 35, 61, 14, 82, 13, 62, 34, 35, 14, 81, 82, 63, 34, 62, 14, 80, 81, 15, 80, 14, 64, 34, 63, 64, 33, 34, 15, 79, 80, 65, 33, 64, 16, 79, 15, 65, 32, 33, 16, 78, 79, 66, 32, 65, 16, 77, 78, 67, 32, 66, 17, 77, 16, 67, 31, 32, 17, 76, 77, 68, 31, 67, 17, 75, 76, 69, 31, 68, 17, 74, 75, 70, 31, 69, 18, 74, 17, 70, 30, 31, 18, 73, 74, 71, 30, 70, 18, 72, 73, 72, 30, 71, 18, 30, 72, 19, 30, 18, 19, 29, 30, 20, 29, 19, 20, 28, 29, 21, 28, 20, 21, 27, 28, 22, 27, 21, 22, 26, 27, 23, 26, 22, 23, 25, 26, 24, 25, 23, 190, 188, 189, 166, 164, 165, 191, 188, 190, 191, 187, 188, 167, 164, 166, 167, 163, 164, 192, 187, 191, 192, 186, 187, 168, 163, 167, 193, 186, 192, 193, 185, 186, 168, 162, 163, 169, 162, 168, 194, 185, 193, 97, 202, 96, 97, 201, 202, 194, 184, 185, 170, 162, 169, 195, 184, 194, 170, 161, 162, 195, 183, 184, 196, 183, 195, 171, 161, 170, 196, 182, 183, 171, 160, 161, 197, 182, 196, 172, 160, 171, 197, 181, 182, 198, 181, 197, 173, 160, 172, 173, 159, 160, 198, 180, 181, 199, 180, 198, 174, 159, 173, 199, 179, 180, 200, 179, 199, 174, 158, 159, 175, 158, 174, 200, 178, 179, 201, 178, 200, 176, 158, 175, 176, 138, 158, 138, 157, 158, 97, 99, 201, 99, 100, 201, 100, 101, 201, 101, 102, 201, 102, 103, 201, 103, 104, 201, 104, 105, 201, 105, 106, 201, 106, 107, 201, 107, 108, 201, 108, 109, 201, 109, 110, 201, 110, 178, 201, 110, 111, 178, 111, 177, 178, 177, 137, 176, 137, 138, 176, 112, 177, 111, 139, 157, 138, 177, 136, 137, 113, 177, 112, 140, 157, 139, 177, 135, 136, 114, 177, 113, 141, 157, 140, 177, 134, 135, 115, 177, 114, 115, 134, 177, 142, 157, 141, 115, 133, 134, 142, 156, 157, 116, 133, 115, 116, 132, 133, 143, 156, 142, 116, 131, 132, 117, 131, 116, 144, 156, 143, 117, 130, 131, 118, 130, 117, 145, 156, 144, 118, 129, 130, 145, 155, 156, 119, 129, 118, 119, 128, 129, 146, 155, 145, 119, 127, 128, 120, 127, 119, 147, 155, 146, 120, 126, 127, 147, 154, 155, 121, 126, 120, 97, 98, 99, 121, 125, 126, 148, 154, 147, 122, 125, 121, 149, 154, 148, 149, 153, 154, 123, 125, 122, 150, 153, 149, 150, 152, 153, 124, 125, 123, 151, 152, 150, 241, 239, 240, 241, 238, 239, 242, 238, 241, 242, 237, 238, 243, 237, 242, 243, 236, 237, 244, 236, 243, 244, 235, 236, 245, 235, 244, 245, 234, 235, 246, 234, 245, 246, 233, 234, 247, 289, 246, 289, 233, 246, 247, 288, 289, 290, 233, 289, 247, 287, 288, 291, 233, 290, 247, 286, 287, 292, 233, 291, 292, 232, 233, 247, 285, 286, 248, 285, 247, 293, 232, 292, 248, 284, 285, 294, 232, 293, 248, 283, 284, 295, 232, 294, 248, 282, 283, 296, 232, 295, 249, 282, 248, 296, 231, 232, 249, 281, 282, 297, 231, 296, 249, 280, 281, 298, 231, 297, 250, 280, 249, 298, 230, 231, 250, 279, 280, 299, 230, 298, 250, 278, 279, 300, 230, 299, 251, 278, 250, 251, 277, 278, 300, 229, 230, 301, 229, 300, 251, 301, 277, 251, 229, 301, 252, 229, 251, 252, 228, 229, 253, 227, 252, 227, 228, 252, 253, 226, 227, 254, 226, 253, 254, 225, 226, 254, 224, 225, 255, 224, 254, 255, 223, 224, 256, 223, 255, 256, 222, 223, 204, 276, 203, 256, 221, 222, 205, 276, 204, 206, 276, 205, 257, 221, 256, 257, 220, 221, 207, 276, 206, 208, 276, 207, 257, 219, 220, 209, 276, 208, 257, 218, 219, 210, 276, 209, 258, 218, 257, 211, 276, 210, 258, 217, 218, 212, 276, 211, 258, 216, 217, 213, 276, 212, 214, 276, 213, 258, 215, 216, 215, 276, 214, 258, 276, 215, 259, 276, 258, 259, 275, 276, 260, 275, 259, 260, 274, 275, 260, 273, 274, 261, 273, 260, 261, 272, 273, 261, 271, 272, 262, 271, 261, 262, 270, 271, 262, 269, 270, 263, 269, 262, 263, 268, 269, 263, 267, 268, 263, 266, 267, 264, 266, 263, 264, 265, 266, 302, 329, 328, 329, 327, 328, 329, 326, 327, 329, 325, 326, 329, 324, 325, 329, 323, 324, 329, 322, 323, 329, 330, 322, 330, 331, 322, 331, 321, 322, 302, 355, 329, 332, 321, 331, 333, 321, 332, 334, 321, 333, 334, 320, 321, 335, 320, 334, 336, 320, 335, 336, 319, 320, 337, 319, 336, 337, 318, 319, 338, 318, 337, 339, 318, 338, 339, 317, 318, 340, 317, 339, 340, 316, 317, 341, 316, 340, 341, 315, 316, 342, 315, 341, 343, 315, 342, 343, 314, 315, 344, 314, 343, 344, 313, 314, 345, 313, 344, 346, 313, 345, 346, 312, 313, 347, 312, 346, 347, 311, 312, 348, 311, 347, 349, 311, 348, 349, 310, 311, 350, 310, 349, 350, 309, 310, 351, 309, 350, 352, 309, 351, 352, 308, 309, 353, 308, 352, 354, 308, 353, 302, 354, 355, 302, 308, 354, 302, 307, 308, 302, 306, 307, 302, 305, 306, 302, 304, 305, 302, 303, 304, 369, 367, 368, 369, 366, 367, 370, 366, 369, 370, 365, 366, 370, 364, 365, 371, 364, 370, 371, 363, 364, 371, 362, 363, 372, 362, 371, 372, 361, 362, 372, 360, 361, 373, 360, 372, 373, 359, 360, 373, 358, 359, 374, 358, 373, 374, 357, 358, 374, 356, 357, 375, 356, 374, 375, 481, 356, 481, 482, 356, 482, 483, 356, 483, 484, 356, 484, 485, 356, 485, 486, 356, 486, 487, 356, 487, 488, 356, 488, 489, 356, 376, 479, 375, 479, 480, 375, 480, 481, 375, 377, 478, 376, 478, 479, 376, 378, 476, 377, 476, 477, 377, 477, 478, 377, 378, 475, 476, 378, 474, 475, 378, 473, 474, 378, 472, 473, 378, 471, 472, 379, 471, 378, 379, 470, 471, 379, 469, 470, 379, 468, 469, 379, 467, 468, 380, 467, 379, 380, 466, 467, 380, 465, 466, 380, 464, 465, 381, 464, 380, 381, 463, 464, 381, 462, 463, 381, 461, 462, 381, 460, 461, 381, 459, 460, 382, 459, 381, 382, 458, 459, 382, 457, 458, 382, 456, 457, 383, 456, 382, 383, 455, 456, 383, 454, 455, 383, 453, 454, 384, 453, 383, 384, 452, 453, 385, 452, 384, 385, 451, 452, 385, 450, 451, 386, 450, 385, 386, 449, 450, 387, 449, 386, 387, 448, 449, 387, 447, 448, 388, 447, 387, 388, 446, 447, 389, 446, 388, 389, 445, 446, 389, 444, 445, 390, 444, 389, 390, 443, 444, 391, 443, 390, 391, 442, 443, 392, 442, 391, 392, 441, 442, 417, 415, 416, 392, 440, 441, 393, 440, 392, 417, 414, 415, 394, 440, 393, 417, 413, 414, 395, 440, 394, 395, 439, 440, 417, 412, 413, 396, 439, 395, 417, 411, 412, 397, 439, 396, 417, 410, 411, 398, 439, 397, 398, 438, 439, 417, 409, 410, 399, 438, 398, 400, 438, 399, 417, 408, 409, 401, 438, 400, 417, 407, 408, 402, 438, 401, 417, 406, 407, 403, 438, 402, 417, 405, 406, 404, 438, 403, 417, 404, 405, 404, 437, 438, 417, 437, 404, 417, 436, 437, 417, 435, 436, 418, 435, 417, 418, 434, 435, 419, 434, 418, 420, 434, 419, 420, 433, 434, 421, 433, 420, 422, 433, 421, 422, 432, 433, 423, 432, 422, 423, 431, 432, 424, 431, 423, 425, 431, 424, 425, 430, 431, 426, 430, 425, 427, 430, 426, 427, 429, 430, 428, 429, 427, 492, 490, 491, 492, 529, 490, 505, 503, 504, 505, 502, 503, 505, 501, 502, 505, 500, 501, 505, 499, 500, 506, 499, 505, 506, 498, 499, 506, 497, 498, 506, 496, 497, 507, 496, 506, 507, 495, 496, 507, 494, 495, 507, 493, 494, 507, 492, 493, 508, 492, 507, 508, 564, 492, 564, 565, 492, 565, 566, 492, 566, 567, 492, 567, 529, 492, 509, 561, 508, 561, 562, 508, 562, 563, 508, 563, 564, 508, 510, 558, 509, 558, 559, 509, 559, 560, 509, 560, 561, 509, 511, 555, 510, 555, 556, 510, 556, 557, 510, 557, 558, 510, 511, 554, 555, 511, 553, 554, 512, 553, 511, 512, 552, 553, 512, 551, 552, 530, 529, 567, 512, 550, 551, 513, 550, 512, 513, 549, 550, 513, 548, 549, 514, 548, 513, 514, 547, 548, 514, 546, 547, 515, 546, 514, 515, 545, 546, 516, 545, 515, 516, 544, 545, 516, 543, 544, 517, 543, 516, 517, 542, 543, 517, 541, 542, 518, 541, 517, 518, 540, 541, 519, 540, 518, 519, 539, 540, 519, 538, 539, 520, 538, 519, 520, 537, 538, 520, 536, 537, 521, 536, 520, 521, 535, 536, 521, 534, 535, 521, 533, 534, 522, 533, 521, 522, 532, 533, 522, 531, 532, 522, 530, 531, 522, 529, 530, 523, 529, 522, 524, 529, 523, 525, 529, 524, 526, 529, 525, 527, 529, 526, 528, 529, 527, 585, 583, 584, 585, 582, 583, 586, 582, 585, 586, 581, 582, 587, 581, 586, 587, 580, 581, 588, 580, 587, 588, 579, 580, 589, 579, 588, 589, 578, 579, 590, 578, 589, 590, 577, 578, 591, 577, 590, 591, 576, 577, 592, 576, 591, 592, 575, 576, 593, 575, 592, 593, 574, 575, 594, 574, 593, 594, 573, 574, 595, 573, 594, 595, 572, 573, 596, 572, 595, 597, 572, 596, 597, 619, 572, 597, 618, 619, 598, 618, 597, 598, 617, 618, 599, 617, 598, 599, 616, 617, 600, 616, 599, 600, 615, 616, 601, 615, 600, 601, 614, 615, 602, 614, 601, 602, 613, 614, 603, 613, 602, 603, 612, 613, 604, 612, 603, 604, 611, 612, 605, 611, 604, 605, 610, 611, 606, 610, 605, 606, 609, 610, 607, 609, 606, 607, 608, 609, 570, 568, 569, 570, 571, 568, 650, 648, 649, 650, 647, 648, 623, 621, 622, 623, 620, 621, 651, 647, 650, 651, 646, 647, 651, 645, 646, 652, 645, 651, 652, 644, 645, 624, 620, 623, 652, 643, 644, 625, 620, 624, 653, 643, 652, 653, 642, 643, 626, 620, 625, 627, 620, 626, 653, 641, 642, 654, 641, 653, 628, 620, 627, 654, 640, 641, 629, 674, 628, 674, 620, 628, 654, 639, 640, 630, 674, 629, 654, 638, 639, 631, 674, 630, 655, 638, 654, 632, 674, 631, 655, 637, 638, 633, 674, 632, 655, 636, 637, 634, 674, 633, 655, 635, 636, 635, 674, 634, 655, 674, 635, 655, 673, 674, 675, 620, 674, 656, 673, 655, 656, 672, 673, 656, 671, 672, 657, 671, 656, 657, 670, 671, 658, 670, 657, 658, 669, 670, 658, 668, 669, 659, 668, 658, 659, 667, 668, 659, 666, 667, 660, 666, 659, 660, 665, 666, 661, 665, 660, 661, 664, 665, 661, 663, 664, 662, 663, 661, 678, 676, 677, 678, 679, 676, 682, 688, 681, 688, 680, 681, 688, 689, 680, 682, 687, 688, 682, 684, 687, 684, 686, 687, 684, 685, 686, 682, 683, 684, 691, 719, 690, 719, 718, 690, 719, 717, 718, 719, 716, 717, 719, 715, 716, 719, 714, 715, 719, 713, 714, 719, 712, 713, 719, 711, 712, 719, 720, 711, 720, 710, 711, 691, 745, 719, 721, 710, 720, 722, 710, 721, 723, 710, 722, 723, 709, 710, 724, 709, 723, 725, 709, 724, 726, 709, 725, 726, 708, 709, 727, 708, 726, 728, 708, 727, 729, 708, 728, 729, 707, 708, 730, 707, 729, 731, 707, 730, 731, 706, 707, 732, 706, 731, 733, 706, 732, 733, 705, 706, 734, 705, 733, 734, 704, 705, 735, 704, 734, 736, 704, 735, 736, 703, 704, 737, 703, 736, 738, 703, 737, 738, 702, 703, 739, 702, 738, 740, 702, 739, 741, 702, 740, 742, 702, 741, 742, 701, 702, 743, 701, 742, 744, 701, 743, 691, 693, 745, 693, 744, 745, 693, 701, 744, 693, 700, 701, 693, 699, 700, 693, 698, 699, 693, 697, 698, 693, 696, 697, 693, 695, 696, 693, 694, 695, 691, 692, 693, 748, 746, 747, 748, 749, 746, 752, 750, 751, 752, 755, 750, 752, 754, 755, 752, 753, 754, 758, 764, 757, 764, 756, 757, 764, 765, 756, 758, 763, 764, 758, 760, 763, 760, 762, 763, 760, 761, 762, 758, 759, 760}); } +void FluidSimulation::_initializeParticleSystems() { + _markerParticles.addAttributeVector3("POSITION"); + _markerParticles.addAttributeVector3("VELOCITY"); + + if (_velocityTransferMethod == VelocityTransferMethod::APIC) { + _markerParticles.addAttributeVector3("AFFINEX"); + _markerParticles.addAttributeVector3("AFFINEY"); + _markerParticles.addAttributeVector3("AFFINEZ"); + } +} + void FluidSimulation::_initializeForceFieldGrid(int isize, int jsize, int ksize, double dx) { int reduction = _forceFieldReductionLevel; int isizeff = (int)std::ceil((double)isize / (double)reduction); @@ -2638,11 +2791,21 @@ vmath::vec3 FluidSimulation::_jitterMarkerParticlePosition(vmath::vec3 p, return p; } -void FluidSimulation::_addMarkerParticle(vmath::vec3 p, vmath::vec3 velocity) { - GridIndex g = Grid3d::positionToGridIndex(p, _dx); - if (Grid3d::isGridIndexInRange(g, _isize, _jsize, _ksize)) { - _markerParticles.push_back(MarkerParticle(p, velocity)); +void FluidSimulation::_addMarkerParticles(std::vector &particles) { + std::vector *positions, *velocities; + _markerParticles.getAttributeValues("POSITION", positions); + _markerParticles.getAttributeValues("VELOCITY", velocities); + + for (size_t i = 0; i < particles.size(); i++) { + MarkerParticle mp = particles[i]; + GridIndex g = Grid3d::positionToGridIndex(mp.position, _dx); + if (Grid3d::isGridIndexInRange(g, _isize, _jsize, _ksize)) { + positions->push_back(mp.position); + velocities->push_back(mp.velocity); + } } + + _markerParticles.update(); } void FluidSimulation::_initializeParticleRadii() { @@ -2664,6 +2827,7 @@ void FluidSimulation::_initializeSimulation() { "Initializing Simulation:" << std::endl); _initializeSimulationGrids(_isize, _jsize, _ksize, _dx); + _initializeParticleSystems(); _initializeParticleRadii(); _initializeRandomGenerator(); @@ -2694,18 +2858,28 @@ void FluidSimulation::_upscaleParticleData() { double dx = _upscalingPreviousCellSize; double particleRadius = 0.5 * _liquidSDFParticleScale * dx * sqrt(3.0); + ParticleSystem markerParticles; + markerParticles.addAttributeVector3("POSITION"); + markerParticles.addAttributeVector3("VELOCITY"); + + std::vector *positions, *velocities; + markerParticles.getAttributeValues("POSITION", positions); + markerParticles.getAttributeValues("VELOCITY", velocities); + AABB bounds(0.0, 0.0, 0.0, isize * dx, jsize * dx, ksize * dx); - FragmentedVector markerParticles; for (size_t j = 0; j < _markerParticleLoadQueue.size(); j++) { for (size_t i = 0; i < _markerParticleLoadQueue[j].particles.size(); i++) { MarkerParticle mp = _markerParticleLoadQueue[j].particles[i]; mp.position = (mp.position - _domainOffset) / _domainScale; if (bounds.isPointInside(mp.position)) { - markerParticles.push_back(mp); + positions->push_back(mp.position); + velocities->push_back(mp.velocity); } } } + markerParticles.update(); + if (markerParticles.empty()) { return; } @@ -2728,8 +2902,8 @@ void FluidSimulation::_upscaleParticleData() { vfield.extrapolateVelocityField(validVelocities, extrapolationLayers); ParticleMaskGrid maskgrid(_isize, _jsize, _ksize, _dx); - for (unsigned int i = 0; i < markerParticles.size(); i++) { - maskgrid.addParticle(markerParticles[i].position); + for (unsigned int i = 0; i < positions->size(); i++) { + maskgrid.addParticle(positions->at(i)); } double q = 0.25 * _dx; @@ -2780,18 +2954,49 @@ void FluidSimulation::_upscaleParticleData() { _isMarkerParticleLoadPending = true; } -void FluidSimulation::_loadMarkerParticles(MarkerParticleLoadData &data) { +void FluidSimulation::_loadMarkerParticles(MarkerParticleLoadData &particleData, + MarkerParticleAffineLoadData &affineData) { + + if (particleData.particles.empty()) { + return; + } + + bool load_affine_data = _velocityTransferMethod == VelocityTransferMethod::APIC && + affineData.particles.size() == particleData.particles.size(); + + _markerParticles.reserve(_markerParticles.size() + particleData.particles.size()); + + std::vector *positions, *velocities; + _markerParticles.getAttributeValues("POSITION", positions); + _markerParticles.getAttributeValues("VELOCITY", velocities); - _markerParticles.reserve(_markerParticles.size() + data.particles.size()); + std::vector *affineX = nullptr; + std::vector *affineY = nullptr; + std::vector *affineZ = nullptr; + if (load_affine_data) { + _markerParticles.getAttributeValues("AFFINEX", affineX); + _markerParticles.getAttributeValues("AFFINEY", affineY); + _markerParticles.getAttributeValues("AFFINEZ", affineZ); + } AABB bounds(0.0, 0.0, 0.0, _isize * _dx, _jsize * _dx, _ksize * _dx); - for (size_t i = 0; i < data.particles.size(); i++) { - MarkerParticle mp = data.particles[i]; + for (size_t i = 0; i < particleData.particles.size(); i++) { + MarkerParticle mp = particleData.particles[i]; mp.position = (mp.position - _domainOffset) / _domainScale; if (bounds.isPointInside(mp.position)) { - _markerParticles.push_back(mp); + positions->push_back(mp.position); + velocities->push_back(mp.velocity); + + if (load_affine_data) { + MarkerParticleAffine ap = affineData.particles[i]; + affineX->push_back(ap.affineX); + affineY->push_back(ap.affineY); + affineZ->push_back(ap.affineZ); + } } } + + _markerParticles.update(); } void FluidSimulation::_loadDiffuseParticles(DiffuseParticleLoadData &data) { @@ -2799,10 +3004,14 @@ void FluidSimulation::_loadDiffuseParticles(DiffuseParticleLoadData &data) { } void FluidSimulation::_loadParticles() { + bool is_affine_data_available = _markerParticleAffineLoadQueue.size() == _markerParticleLoadQueue.size(); + MarkerParticleAffineLoadData emptyAffineData; for (size_t i = 0; i < _markerParticleLoadQueue.size(); i++) { - _loadMarkerParticles(_markerParticleLoadQueue[i]); + MarkerParticleAffineLoadData affineData = is_affine_data_available ? _markerParticleAffineLoadQueue[i] : emptyAffineData; + _loadMarkerParticles(_markerParticleLoadQueue[i], affineData); } _markerParticleLoadQueue.clear(); + _markerParticleAffineLoadQueue.clear(); _isMarkerParticleLoadPending = false; for (size_t i = 0; i < _diffuseParticleLoadQueue.size(); i++) { @@ -3274,6 +3483,12 @@ _logfile.logString(_logfile.getTime() + " BEGIN Advect Velocity Field"); params.vfield = &_MACVelocity; params.validVelocities = &_validVelocities; params.particleRadius = _liquidSDFParticleRadius; + + if (_velocityTransferMethod == VelocityTransferMethod::FLIP) { + params.velocityTransferMethod = VelocityAdvectorTransferMethod::FLIP; + } else if (_velocityTransferMethod == VelocityTransferMethod::APIC) { + params.velocityTransferMethod = VelocityAdvectorTransferMethod::APIC; + } _velocityAdvector.advect(params); @@ -3400,7 +3615,6 @@ void FluidSimulation::_getInflowConstrainedVelocityComponents(ValidVelocityCompo float frameInterpolation = frameProgress + (float)subidx * substepFactor; inflow->setFrame(_currentFrame, frameInterpolation); inflow->update(_currentFrameDeltaTime); - MeshLevelSet *inflowSDF = inflow->getMeshLevelSet(); for (int k = 0; k < _ksize; k++) { for (int j = 0; j < _jsize; j++) { @@ -3409,7 +3623,7 @@ void FluidSimulation::_getInflowConstrainedVelocityComponents(ValidVelocityCompo continue; } vmath::vec3 p = Grid3d::FaceIndexToPositionU(i, j, k, _dx); - if (inflowSDF->trilinearInterpolate(p) < 0.0f) { + if (inflow->trilinearInterpolate(p) < 0.0f) { ex.validU.set(i, j, k, true); } } @@ -3423,7 +3637,7 @@ void FluidSimulation::_getInflowConstrainedVelocityComponents(ValidVelocityCompo continue; } vmath::vec3 p = Grid3d::FaceIndexToPositionV(i, j, k, _dx); - if (inflowSDF->trilinearInterpolate(p) < 0.0f) { + if (inflow->trilinearInterpolate(p) < 0.0f) { ex.validV.set(i, j, k, true); } } @@ -3437,7 +3651,7 @@ void FluidSimulation::_getInflowConstrainedVelocityComponents(ValidVelocityCompo continue; } vmath::vec3 p = Grid3d::FaceIndexToPositionW(i, j, k, _dx); - if (inflowSDF->trilinearInterpolate(p) < 0.0f) { + if (inflow->trilinearInterpolate(p) < 0.0f) { ex.validW.set(i, j, k, true); } } @@ -3638,10 +3852,11 @@ void FluidSimulation::_applyViscosityToVelocityField(double dt) { params.liquidSDF = &_liquidSDF; params.solidSDF = &_solidSDF; params.viscosity = &_viscosity; + params.errorTolerance = _viscositySolverErrorTolerance; - ViscositySolver vsolver; - vsolver.applyViscosityToVelocityField(params); - _viscositySolverStatus = vsolver.getSolverStatus(); + _viscositySolver = ViscositySolver(); + _viscositySolver.applyViscosityToVelocityField(params); + _viscositySolverStatus = _viscositySolver.getSolverStatus(); t.stop(); _timingData.applyViscosityToVelocityField += t.getTime(); @@ -4056,6 +4271,10 @@ void FluidSimulation::_updateSheetSeeding() { ParticleSheeter sheeter; sheeter.generateSheetParticles(params, sheetParticles); + std::vector *positions, *velocities; + _markerParticles.getAttributeValues("POSITION", positions); + _markerParticles.getAttributeValues("VELOCITY", velocities); + float solidSheetingWidth = 2.0f * _dx; for (size_t i = 0; i < sheetParticles.size(); i++) { vmath::vec3 p = sheetParticles[i]; @@ -4075,10 +4294,12 @@ void FluidSimulation::_updateSheetSeeding() { } vmath::vec3 v = _savedVelocityField.evaluateVelocityAtPositionLinear(p); - MarkerParticle m(p, v); - _markerParticles.push_back(m); + positions->push_back(p); + velocities->push_back(v); } + _markerParticles.update(); + t.stop(); _timingData.updateSheetSeeding += t.getTime(); @@ -4089,26 +4310,155 @@ void FluidSimulation::_updateSheetSeeding() { #. Update MarkerParticle Velocities ********************************************************************************/ +void FluidSimulation::_getIndicesAndGradientWeights(vmath::vec3 p, GridIndex indices[8], vmath::vec3 weights[8], int dir) { + int U = 0; int V = 1; int W = 2; + + vmath::vec3 offset; + float h = 0.5f * _dx; + if (dir == U) { + offset = vmath::vec3(0.0f, h, h); + } else if (dir == V) { + offset = vmath::vec3(h, 0.0f, h); + } else if (dir == W) { + offset = vmath::vec3(h, h, 0.0f); + } + + p -= offset; + GridIndex g = Grid3d::positionToGridIndex(p, _dx); + vmath::vec3 gpos = Grid3d::GridIndexToPosition(g, _dx); + vmath::vec3 ipos = (p - gpos) / _dx; + + indices[0] = GridIndex(g.i, g.j, g.k); + indices[1] = GridIndex(g.i + 1, g.j, g.k); + indices[2] = GridIndex(g.i, g.j + 1, g.k); + indices[3] = GridIndex(g.i + 1, g.j + 1, g.k); + indices[4] = GridIndex(g.i, g.j, g.k + 1); + indices[5] = GridIndex(g.i + 1, g.j, g.k + 1); + indices[6] = GridIndex(g.i, g.j + 1, g.k + 1); + indices[7] = GridIndex(g.i + 1, g.j + 1, g.k + 1); + + float invdx = 1.0f / _dx; + weights[0] = vmath::vec3( + -invdx * (1.0f - ipos.y) * (1.0f - ipos.z), + -invdx * (1.0f - ipos.x) * (1.0f - ipos.z), + -invdx * (1.0f - ipos.x) * (1.0f - ipos.y)); + weights[1] = vmath::vec3( + invdx * (1.0f - ipos.y) * (1.0f - ipos.z), + ipos.x * (-invdx) * (1.0f - ipos.z), + ipos.x * (1.0f - ipos.y) * (-invdx)); + weights[2] = vmath::vec3( + (-invdx) * ipos.y * (1.0f - ipos.z), + (1.0f - ipos.x) * invdx * (1.0f - ipos.z), + (1.0f - ipos.x) * ipos.y * (-invdx)); + weights[3] = vmath::vec3( + invdx * ipos.y * (1.0f - ipos.z), + ipos.x * invdx * (1.0f - ipos.z), + ipos.x * ipos.y * (-invdx)); + weights[4] = vmath::vec3( + (-invdx) * (1.0f - ipos.y) * ipos.z, + (1.0f - ipos.x) * (-invdx) * ipos.z, + (1.0f - ipos.x) * (1.0f - ipos.y) * invdx); + weights[5] = vmath::vec3( + invdx * (1.0f - ipos.y) * ipos.z, + ipos.x * (-invdx) * ipos.z, + ipos.x * (1.0f - ipos.y) * invdx); + weights[6] = vmath::vec3( + (-invdx) * ipos.y * ipos.z, + (1.0f - ipos.x) * invdx * ipos.z, + (1.0f - ipos.x) * ipos.y * invdx); + weights[7] = vmath::vec3( + invdx * ipos.y * ipos.z, + ipos.x * invdx * ipos.z, + ipos.x * ipos.y * invdx); +} + void FluidSimulation::_updatePICFLIPMarkerParticleVelocitiesThread(int startidx, int endidx) { + std::vector *positions, *velocities; + _markerParticles.getAttributeValues("POSITION", positions); + _markerParticles.getAttributeValues("VELOCITY", velocities); + for (int i = startidx; i < endidx; i++) { - MarkerParticle mp = _markerParticles[i]; - vmath::vec3 vPIC = _MACVelocity.evaluateVelocityAtPositionLinear(mp.position); - vmath::vec3 vFLIP = mp.velocity + vPIC - - _savedVelocityField.evaluateVelocityAtPositionLinear(mp.position); + vmath::vec3 pos = positions->at(i); + vmath::vec3 vel = velocities->at(i); + vmath::vec3 vPIC = _MACVelocity.evaluateVelocityAtPositionLinear(pos); + vmath::vec3 vFLIP = vel + vPIC - _savedVelocityField.evaluateVelocityAtPositionLinear(pos); vmath::vec3 v = (float)_ratioPICFLIP * vPIC + (float)(1 - _ratioPICFLIP) * vFLIP; + velocities->at(i) = v; + } +} + +/* + The APIC (Affine Particle-In-Cell) velocity transfer method was adapted from + Doyub Kim's 'Fluid Engine Dev' repository: + https://github.com/doyubkim/fluid-engine-dev +*/ +void FluidSimulation::_updatePICAPICMarkerParticleVelocitiesThread(int startidx, int endidx) { + std::vector *positions, *velocities; + std::vector *affineValuesX, *affineValuesY, *affineValuesZ; + _markerParticles.getAttributeValues("POSITION", positions); + _markerParticles.getAttributeValues("VELOCITY", velocities); + _markerParticles.getAttributeValues("AFFINEX", affineValuesX); + _markerParticles.getAttributeValues("AFFINEY", affineValuesY); + _markerParticles.getAttributeValues("AFFINEZ", affineValuesZ); + + int U = 0; int V = 1; int W = 2; + + GridIndex indices[8]; + vmath::vec3 weights[8]; + for (int i = startidx; i < endidx; i++) { + vmath::vec3 pos = positions->at(i); + + vmath::vec3 affineX; + vmath::vec3 affineY; + vmath::vec3 affineZ; + + _getIndicesAndGradientWeights(pos, indices, weights, U); + for (int gidx = 0; gidx < 8; gidx++) { + GridIndex g = indices[gidx]; + if (!_MACVelocity.isIndexInRangeU(g)) { + continue; + } + affineX += weights[gidx] * _MACVelocity.U(g); + } - _markerParticles[i].velocity = v; + _getIndicesAndGradientWeights(pos, indices, weights, V); + for (int gidx = 0; gidx < 8; gidx++) { + GridIndex g = indices[gidx]; + if (!_MACVelocity.isIndexInRangeV(g)) { + continue; + } + affineY += weights[gidx] * _MACVelocity.V(g); + } + + _getIndicesAndGradientWeights(pos, indices, weights, W); + for (int gidx = 0; gidx < 8; gidx++) { + GridIndex g = indices[gidx]; + if (!_MACVelocity.isIndexInRangeW(g)) { + continue; + } + affineZ += weights[gidx] * _MACVelocity.W(g); + } + + velocities->at(i) = _MACVelocity.evaluateVelocityAtPositionLinear(pos); + affineValuesX->at(i) = affineX; + affineValuesY->at(i) = affineY; + affineValuesZ->at(i) = affineZ; } } -void FluidSimulation::_updatePICFLIPMarkerParticleVelocities() { +void FluidSimulation::_updateMarkerParticleVelocitiesThread() { int numCPU = ThreadUtils::getMaxThreadCount(); int numthreads = (int)fmin(numCPU, _markerParticles.size()); std::vector threads(numthreads); std::vector intervals = ThreadUtils::splitRangeIntoIntervals(0, _markerParticles.size(), numthreads); for (int i = 0; i < numthreads; i++) { - threads[i] = std::thread(&FluidSimulation::_updatePICFLIPMarkerParticleVelocitiesThread, this, - intervals[i], intervals[i + 1]); + if (_velocityTransferMethod == VelocityTransferMethod::FLIP) { + threads[i] = std::thread(&FluidSimulation::_updatePICFLIPMarkerParticleVelocitiesThread, this, + intervals[i], intervals[i + 1]); + } else if (_velocityTransferMethod == VelocityTransferMethod::APIC) { + threads[i] = std::thread(&FluidSimulation::_updatePICAPICMarkerParticleVelocitiesThread, this, + intervals[i], intervals[i + 1]); + } } for (int i = 0; i < numthreads; i++) { @@ -4137,12 +4487,16 @@ void FluidSimulation::_constrainMarkerParticleVelocities(MeshFluidSource *inflow isInflowCell.fill(false); isInflowCell.set(inflowCells, true); + std::vector *positions, *velocities; + _markerParticles.getAttributeValues("POSITION", positions); + _markerParticles.getAttributeValues("VELOCITY", velocities); + MeshLevelSet *inflowSDF = inflow->getMeshLevelSet(); vmath::vec3 v = inflow->getVelocity(); RigidBodyVelocity rv = inflow->getRigidBodyVelocity(_currentFrameDeltaTime); VelocityFieldData *vdata = inflow->getVelocityFieldData(); - for (size_t i = 0; i < _markerParticles.size(); i++) { - vmath::vec3 p = _markerParticles[i].position; + for (size_t i = 0; i < positions->size(); i++) { + vmath::vec3 p = positions->at(i); GridIndex g = Grid3d::positionToGridIndex(p, _dx); if (!isInflowCell(g)) { continue; @@ -4155,14 +4509,14 @@ void FluidSimulation::_constrainMarkerParticleVelocities(MeshFluidSource *inflow if (inflow->isAppendObjectVelocityEnabled()) { if (inflow->isRigidBody()) { vmath::vec3 tv = vmath::cross(rv.angular * rv.axis, p - rv.centroid); - _markerParticles[i].velocity = v + rv.linear + tv; + velocities->at(i) = v + rv.linear + tv; } else { vmath::vec3 datap = p - vdata->offset; vmath::vec3 fv = vdata->vfield.evaluateVelocityAtPositionLinear(datap); - _markerParticles[i].velocity = v + fv; + velocities->at(i) = v + fv; } } else { - _markerParticles[i].velocity = v; + velocities->at(i) = v; } } } @@ -4185,7 +4539,7 @@ void FluidSimulation::_updateMarkerParticleVelocities() { StopWatch t; t.start(); - _updatePICFLIPMarkerParticleVelocities(); + _updateMarkerParticleVelocitiesThread(); _constrainMarkerParticleVelocities(); t.stop(); @@ -4306,10 +4660,13 @@ vmath::vec3 FluidSimulation::_resolveCollision(vmath::vec3 oldp, vmath::vec3 new } float FluidSimulation::_getMarkerParticleSpeedLimit(double dt) { + std::vector *velocities; + _markerParticles.getAttributeValues("VELOCITY", velocities); + double speedLimitStep = _CFLConditionNumber * _dx / dt; std::vector speedLimitCounts(_maxFrameTimeSteps, 0); - for (unsigned int i = 0; i < _markerParticles.size(); i++) { - double speed = (double)_markerParticles[i].velocity.length(); + for (unsigned int i = 0; i < velocities->size(); i++) { + double speed = (double)velocities->at(i).length(); int speedLimitIndex = fmin(floor(speed / speedLimitStep), _maxFrameTimeSteps - 1); speedLimitCounts[speedLimitIndex]++; } @@ -4337,15 +4694,21 @@ void FluidSimulation::_removeMarkerParticles(double dt) { float maxspeed = _getMarkerParticleSpeedLimit(dt); double maxspeedsq = maxspeed * maxspeed; + std::vector *positions, *velocities; + _markerParticles.getAttributeValues("POSITION", positions); + _markerParticles.getAttributeValues("VELOCITY", velocities); + std::vector isRemoved; - _solidSDF.trilinearInterpolateSolidPoints(_markerParticles, isRemoved); + _solidSDF.trilinearInterpolateSolidPoints(*positions, isRemoved); for (unsigned int i = 0; i < _markerParticles.size(); i++) { if (isRemoved[i]) { continue; } - MarkerParticle mp = _markerParticles[i]; - GridIndex g = Grid3d::positionToGridIndex(mp.position, _dx); + vmath::vec3 position = positions->at(i); + vmath::vec3 velocity = velocities->at(i); + + GridIndex g = Grid3d::positionToGridIndex(position, _dx); if (countGrid(g) >= _maxMarkerParticlesPerCell) { isRemoved[i] = true; continue; @@ -4353,13 +4716,13 @@ void FluidSimulation::_removeMarkerParticles(double dt) { countGrid.add(g, 1); if (_isExtremeVelocityRemovalEnabled && - vmath::dot(mp.velocity, mp.velocity) > maxspeedsq) { + vmath::dot(velocity, velocity) > maxspeedsq) { isRemoved[i] = true; continue; } } - _removeItemsFromVector(_markerParticles, isRemoved); + _markerParticles.removeParticles(isRemoved); } void FluidSimulation::_advanceMarkerParticles(double dt) { @@ -4367,21 +4730,21 @@ void FluidSimulation::_advanceMarkerParticles(double dt) { StopWatch t; t.start(); + + std::vector *positions, *velocities; + _markerParticles.getAttributeValues("POSITION", positions); + _markerParticles.getAttributeValues("VELOCITY", velocities); - std::vector positions; - positions.reserve(_markerParticles.size()); - for (size_t i = 0; i < _markerParticles.size(); i++) { - positions.push_back(_markerParticles[i].position); - } + std::vector positionsCopy = *positions; int numCPU = ThreadUtils::getMaxThreadCount(); - int numthreads = (int)fmin(numCPU, positions.size()); + int numthreads = (int)fmin(numCPU, positionsCopy.size()); std::vector threads(numthreads); - std::vector output(positions.size()); - std::vector intervals = ThreadUtils::splitRangeIntoIntervals(0, positions.size(), numthreads); + std::vector output(positionsCopy.size()); + std::vector intervals = ThreadUtils::splitRangeIntoIntervals(0, positionsCopy.size(), numthreads); for (int i = 0; i < numthreads; i++) { threads[i] = std::thread(&FluidSimulation::_advanceMarkerParticlesThread, this, - dt, intervals[i], intervals[i + 1], &positions, &output); + dt, intervals[i], intervals[i + 1], &positionsCopy, &output); } for (int i = 0; i < numthreads; i++) { @@ -4389,7 +4752,14 @@ void FluidSimulation::_advanceMarkerParticles(double dt) { } for (size_t i = 0; i < _markerParticles.size(); i++) { - _markerParticles[i].position = output[i]; + float distanceTravelled = vmath::length(positions->at(i) - output[i]); + if (distanceTravelled < 1e-6) { + // In the rare case that a particle did not move, it could be + // that this particle is stuck. Velocity should be set to 0.0 + // which helps the particle 'reset' and become unstuck. + //velocities->at(i) = vmath::vec3(); + } + positions->at(i) = output[i]; } _removeMarkerParticles(_currentFrameDeltaTime); @@ -4426,6 +4796,7 @@ void FluidSimulation::_addNewFluidCells(std::vector &cells, threads[i].join(); } + std::vector newParticles; for (size_t vidx = 0; vidx < particleVectors.size(); vidx++) { for (size_t i = 0; i < particleVectors[vidx].size(); i++) { vmath::vec3 p = particleVectors[vidx][i]; @@ -4433,10 +4804,12 @@ void FluidSimulation::_addNewFluidCells(std::vector &cells, continue; } - _addMarkerParticle(p, velocity); + newParticles.push_back(MarkerParticle(p, velocity)); maskgrid.addParticle(p); } } + + _addMarkerParticles(newParticles); } void FluidSimulation::_addNewFluidCells(std::vector &cells, @@ -4462,6 +4835,7 @@ void FluidSimulation::_addNewFluidCells(std::vector &cells, threads[i].join(); } + std::vector newParticles; for (size_t vidx = 0; vidx < particleVectors.size(); vidx++) { for (size_t i = 0; i < particleVectors[vidx].size(); i++) { vmath::vec3 p = particleVectors[vidx][i]; @@ -4471,10 +4845,12 @@ void FluidSimulation::_addNewFluidCells(std::vector &cells, vmath::vec3 rotv = vmath::cross(rvelocity.angular * rvelocity.axis, p - rvelocity.centroid); vmath::vec3 totv = velocity + rvelocity.linear + rotv; - _addMarkerParticle(p, totv); + newParticles.push_back(MarkerParticle(p, totv)); maskgrid.addParticle(p); } } + + _addMarkerParticles(newParticles); } void FluidSimulation::_addNewFluidCells(std::vector &cells, @@ -4496,14 +4872,13 @@ void FluidSimulation::_addNewFluidCells(std::vector &cells, }; double jitter = _getMarkerParticleJitter(); - GridIndex g; - vmath::vec3 p; + std::vector newParticles; for (size_t i = 0; i < cells.size(); i++) { - g = cells[i]; + GridIndex g = cells[i]; vmath::vec3 c = Grid3d::GridIndexToCellCenter(g, _dx); for (unsigned int oidx = 0; oidx < 8; oidx++) { - p = c + particleOffsets[oidx]; + vmath::vec3 p = c + particleOffsets[oidx]; if (maskgrid.isSubCellSet(p)) { continue; } @@ -4522,11 +4897,13 @@ void FluidSimulation::_addNewFluidCells(std::vector &cells, vmath::vec3 fv = vdata->vfield.evaluateVelocityAtPositionLinear(datap); vmath::vec3 v = velocity + fv; - _addMarkerParticle(p, v); + newParticles.push_back(MarkerParticle(p, v)); maskgrid.addParticle(p); } } } + + _addMarkerParticles(newParticles); } void FluidSimulation::_addNewFluidCellsThread(int startidx, int endidx, @@ -4643,10 +5020,13 @@ void FluidSimulation::_updateOutflowMeshFluidSource(MeshFluidSource *source) { isOutflowCell.set(sourceCells, true); } + std::vector *positions; + _markerParticles.getAttributeValues("POSITION", positions); + if (source->isFluidOutflowEnabled()) { std::vector isRemoved(_markerParticles.size(), false); - for (int i = 0; i < (int)_markerParticles.size(); i++) { - vmath::vec3 p = _markerParticles[i].position; + for (size_t i = 0; i < _markerParticles.size(); i++) { + vmath::vec3 p = positions->at(i); GridIndex g = Grid3d::positionToGridIndex(p, _dx); if (isOutflowCell(g)) { float d = sourceSDF->trilinearInterpolate(p - offset); @@ -4657,14 +5037,17 @@ void FluidSimulation::_updateOutflowMeshFluidSource(MeshFluidSource *source) { } } } - _removeItemsFromVector(_markerParticles, isRemoved); + _markerParticles.removeParticles(isRemoved); } if (source->isDiffuseOutflowEnabled()) { - FragmentedVector* dps = _diffuseMaterial.getDiffuseParticles(); + std::vector *positions; + ParticleSystem* dps = _diffuseMaterial.getDiffuseParticles(); + dps->getAttributeValues("POSITION", positions); + std::vector isRemoved(dps->size(), false); - for (int i = 0; i < (int)dps->size(); i++) { - vmath::vec3 p = dps->at(i).position; + for (size_t i = 0; i < dps->size(); i++) { + vmath::vec3 p = positions->at(i); GridIndex g = Grid3d::positionToGridIndex(p, _dx); if (!isOutflowCell.isIndexInRange(g)) { continue; @@ -4679,7 +5062,7 @@ void FluidSimulation::_updateOutflowMeshFluidSource(MeshFluidSource *source) { } } } - _removeItemsFromVector(*dps, isRemoved); + dps->removeParticles(isRemoved); } } @@ -4695,9 +5078,12 @@ void FluidSimulation::_updateInflowMeshFluidSources() { return; } + std::vector *positions; + _markerParticles.getAttributeValues("POSITION", positions); + ParticleMaskGrid maskgrid(_isize, _jsize, _ksize, _dx); for (unsigned int i = 0; i < _markerParticles.size(); i++) { - maskgrid.addParticle(_markerParticles[i].position); + maskgrid.addParticle(positions->at(i)); } for (size_t i = 0; i < _meshFluidSources.size(); i++) { @@ -4736,9 +5122,12 @@ void FluidSimulation::_updateAddedFluidMeshObjectQueue() { return; } + std::vector *positions; + _markerParticles.getAttributeValues("POSITION", positions); + ParticleMaskGrid maskgrid(_isize, _jsize, _ksize, _dx); - for (unsigned int i = 0; i < _markerParticles.size(); i++) { - maskgrid.addParticle(_markerParticles[i].position); + for (unsigned int i = 0; i < positions->size(); i++) { + maskgrid.addParticle(positions->at(i)); } MeshLevelSet meshSDF(_isize, _jsize, _ksize, _dx); @@ -4780,10 +5169,13 @@ int FluidSimulation::_getNumFluidCells() { } } + std::vector *positions; + _markerParticles.getAttributeValues("POSITION", positions); + if (count == 0 && !_markerParticles.empty()) { Array3d isFluidCell(_isize, _jsize, _ksize, false); - for (unsigned int i = 0; i < _markerParticles.size(); i++) { - GridIndex g = Grid3d::positionToGridIndex(_markerParticles[i].position, _dx); + for (unsigned int i = 0; i < positions->size(); i++) { + GridIndex g = Grid3d::positionToGridIndex(positions->at(i), _dx); isFluidCell.set(g, true); } @@ -5308,11 +5700,14 @@ void FluidSimulation::_outputSurfaceMeshThread(std::vector *particl } void FluidSimulation::_launchOutputSurfaceMeshThread() { + std::vector *positions; + _markerParticles.getAttributeValues("POSITION", positions); + // Particles will be deleted within the thread after use std::vector *particles = new std::vector(); - particles->reserve(_markerParticles.size()); - for (size_t i = 0; i < _markerParticles.size(); i++) { - particles->push_back(_markerParticles[i].position); + particles->reserve(positions->size()); + for (size_t i = 0; i < positions->size(); i++) { + particles->push_back(positions->at(i)); } // solidSDF will be deleted within the thread after use @@ -5345,6 +5740,7 @@ void FluidSimulation::_outputDiffuseMaterial() { &nbubble, &nspray, &ndust); + _outputData.frameData.foam.enabled = 1; _outputData.frameData.foam.vertices = nfoam; _outputData.frameData.foam.triangles = 0; @@ -5399,13 +5795,16 @@ void FluidSimulation::_outputDiffuseMaterial() { } float FluidSimulation::_calculateParticleSpeedPercentileThreshold(float pct) { + std::vector *velocities; + _markerParticles.getAttributeValues("VELOCITY", velocities); + float eps = 1e-3; float maxs = fmax(_getMaximumMarkerParticleSpeed(), eps); float invmax = 1.0f / maxs; int nbins = 10000; std::vector binCounts(nbins, 0); for (size_t i = 0; i < _markerParticles.size(); i++) { - float s = vmath::length(_markerParticles[i].velocity); + float s = vmath::length(velocities->at(i)); int binidx = (int)fmin(floor(s * invmax * (nbins - 1)), nbins - 1); binCounts[binidx]++; } @@ -5428,12 +5827,16 @@ float FluidSimulation::_calculateParticleSpeedPercentileThreshold(float pct) { void FluidSimulation::_outputFluidParticles() { if (!_isFluidParticleOutputEnabled) { return; } + std::vector *positions, *velocities; + _markerParticles.getAttributeValues("POSITION", positions); + _markerParticles.getAttributeValues("VELOCITY", velocities); + float maxSpeed = _calculateParticleSpeedPercentileThreshold(0.995); float invmax = 1.0f / maxSpeed; int nbins = 1024; std::vector binCounts(nbins, 0); - for (size_t i = 0; i < _markerParticles.size(); i++) { - float s = vmath::length(_markerParticles[i].velocity); + for (size_t i = 0; i < velocities->size(); i++) { + float s = vmath::length(velocities->at(i)); int binidx = (int)fmin(floor(s * invmax * (nbins - 1)), nbins - 1); binCounts[binidx]++; } @@ -5450,13 +5853,13 @@ void FluidSimulation::_outputFluidParticles() { std::vector sortedParticles(_markerParticles.size()); std::vector binStartsCopy = binStarts; - for (size_t i = 0; i < _markerParticles.size(); i++) { - float s = vmath::length(_markerParticles[i].velocity); + for (size_t i = 0; i < velocities->size(); i++) { + float s = vmath::length(velocities->at(i)); int binidx = (int)fmin(floor(s * invmax * (nbins - 1)), nbins - 1); int vidx = binStartsCopy[binidx]; binStartsCopy[binidx]++; - vmath::vec3 p = _markerParticles[i].position; + vmath::vec3 p = positions->at(i); p *= _domainScale; p += _domainOffset; sortedParticles[vidx] = p; @@ -5641,11 +6044,13 @@ double FluidSimulation::_predictMaximumMarkerParticleSpeed(double dt) { } double FluidSimulation::_getMaximumMarkerParticleSpeed() { + std::vector *velocities; + _markerParticles.getAttributeValues("VELOCITY", velocities); + double maxsq = 0.0; - MarkerParticle mp; - for (unsigned int i = 0; i < _markerParticles.size(); i++) { - mp = _markerParticles[i]; - double distsq = vmath::dot(mp.velocity, mp.velocity); + for (unsigned int i = 0; i < velocities->size(); i++) { + vmath::vec3 v = velocities->at(i); + double distsq = vmath::dot(v, v); if (distsq > maxsq) { maxsq = distsq; } diff --git a/src/engine/fluidsimulation.h b/src/engine/fluidsimulation.h index 5a0ff646..c389cb42 100644 --- a/src/engine/fluidsimulation.h +++ b/src/engine/fluidsimulation.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -48,13 +48,15 @@ SOFTWARE. #include "meshfluidsource.h" #include "influencegrid.h" #include "forcefieldgrid.h" +#include "particlesystem.h" +#include "markerparticle.h" +#include "viscositysolver.h" class AABB; class MeshFluidSource; class ParticleMaskGrid; class MACVelocityField; class FluidMaterialGrid; -struct MarkerParticle; struct DiffuseParticle; enum class LimitBehaviour : char; @@ -106,6 +108,13 @@ struct FluidSimulationMarkerParticleData { char *velocities; }; +struct FluidSimulationMarkerParticleAffineData { + int size = 0; + char *affineX; + char *affineY; + char *affineZ; +}; + struct FluidSimulationDiffuseParticleData { int size = 0; char *positions; @@ -799,6 +808,13 @@ class FluidSimulation double getViscosity(); void setViscosity(double v); + /* + Error tolerance of the viscosity solver. + Recommended range around [1e-1, 1e-6]. + */ + double getViscositySolverErrorTolerance(); + void setViscositySolverErrorTolerance(double tol); + /* Surface tension constant of the fluid. Must be greater than or equal to zero. @@ -880,10 +896,20 @@ class FluidSimulation bool isExtremeVelocityRemovalEnabled(); /* - Ratio of PIC to FLIP velocity update + Set FLIP (splashy) or APIC (swirly) velocity transfer method + */ + void setVelocityTransferMethodFLIP(); + void setVelocityTransferMethodAPIC(); + bool isVelocityTransferMethodFLIP(); + bool isVelocityTransferMethodAPIC(); + + /* + Ratio of PIC to FLIP or PIC to APIC velocity update */ double getPICFLIPRatio(); void setPICFLIPRatio(double r); + double getPICAPICRatio(); + void setPICAPICRatio(double r); /* Name of the preferred GPU device to use for GPU acceleration features @@ -1024,14 +1050,6 @@ class FluidSimulation */ unsigned int getNumDiffuseParticles(); - /* - Returns a vector of all diffuse particles in the simulation. Diffuse particles - store a position, velocity, lifetime, and and type (bubble, spray, - or foam). - */ - std::vector getDiffuseParticles(); - std::vector getDiffuseParticles(int startidx, int endidx); - /* Returns a vector of diffuse particle positions. If range indices are specified, the vector will contain positions ranging from @@ -1100,6 +1118,9 @@ class FluidSimulation void getMarkerParticlePositionDataRange(int start_idx, int end_idx, char *data); void getMarkerParticleVelocityDataRange(int start_idx, int end_idx, char *data); + void getMarkerParticleAffineXDataRange(int start_idx, int end_idx, char *data); + void getMarkerParticleAffineYDataRange(int start_idx, int end_idx, char *data); + void getMarkerParticleAffineZDataRange(int start_idx, int end_idx, char *data); void getDiffuseParticlePositionDataRange(int start_idx, int end_idx, char *data); void getDiffuseParticleVelocityDataRange(int start_idx, int end_idx, char *data); void getDiffuseParticleLifetimeDataRange(int start_idx, int end_idx, char *data); @@ -1125,10 +1146,16 @@ class FluidSimulation Load char data representing marker/diffuse particles into the simulator */ void loadMarkerParticleData(FluidSimulationMarkerParticleData data); + void loadMarkerParticleAffineData(FluidSimulationMarkerParticleAffineData data); void loadDiffuseParticleData(FluidSimulationDiffuseParticleData data); private: + enum class VelocityTransferMethod : char { + FLIP = 0x00, + APIC = 0x01 + }; + struct FluidMeshObject { MeshObject object; vmath::vec3 velocity; @@ -1163,6 +1190,10 @@ class FluidSimulation FragmentedVector particles; }; + struct MarkerParticleAffineLoadData { + FragmentedVector particles; + }; + struct DiffuseParticleLoadData { FragmentedVector particles; }; @@ -1236,15 +1267,17 @@ class FluidSimulation void _initializeLogFile(); void _initializeSimulationGrids(int isize, int jsize, int ksize, double dx); void _initializeForceFieldGrid(int isize, int jsize, int ksize, double dx); + void _initializeParticleSystems(); void _initializeSimulation(); void _initializeParticleRadii(); void _initializeRandomGenerator(); double _getMarkerParticleJitter(); vmath::vec3 _jitterMarkerParticlePosition(vmath::vec3 p, double jitter); - void _addMarkerParticle(vmath::vec3 p, vmath::vec3 velocity); + void _addMarkerParticles(std::vector &particles); void _upscaleParticleData(); void _loadParticles(); - void _loadMarkerParticles(MarkerParticleLoadData &data); + void _loadMarkerParticles(MarkerParticleLoadData &particleData, + MarkerParticleAffineLoadData &affineData); void _loadDiffuseParticles(DiffuseParticleLoadData &data); /* @@ -1363,8 +1396,10 @@ class FluidSimulation Update MarkerParticle Velocities */ void _updateMarkerParticleVelocities(); - void _updatePICFLIPMarkerParticleVelocities(); + void _updateMarkerParticleVelocitiesThread(); void _updatePICFLIPMarkerParticleVelocitiesThread(int startidx, int endidx); + void _updatePICAPICMarkerParticleVelocitiesThread(int startidx, int endidx); + void _getIndicesAndGradientWeights(vmath::vec3 p, GridIndex indices[8], vmath::vec3 weights[8], int dir); void _constrainMarkerParticleVelocities(); void _constrainMarkerParticleVelocities(MeshFluidSource *inflow); @@ -1460,26 +1495,7 @@ class FluidSimulation Misc Methods */ template - void _removeItemsFromVector(FragmentedVector &items, std::vector &isRemoved) { - FLUIDSIM_ASSERT(items.size() == isRemoved.size()); - - int currentidx = 0; - for (unsigned int i = 0; i < items.size(); i++) { - if (!isRemoved[i]) { - items[currentidx] = items[i]; - currentidx++; - } - } - - int numRemoved = items.size() - currentidx; - for (int i = 0; i < numRemoved; i++) { - items.pop_back(); - } - items.shrink_to_fit(); - } - - template - void _removeItemsFromVector(std::vector &items, std::vector &isRemoved) { + void _removeItemsFromVector(T &items, std::vector &isRemoved) { FLUIDSIM_ASSERT(items.size() == isRemoved.size()); int currentidx = 0; @@ -1548,7 +1564,7 @@ class FluidSimulation // Update fluid material ParticleLevelSet _liquidSDF; std::vector _meshFluidSources; - FragmentedVector _markerParticles; + ParticleSystem _markerParticles; std::vector _addedFluidMeshObjectQueue; double _markerParticleJitterFactor = 0.0; bool _isJitterSurfaceMarkerParticlesEnabled = false; @@ -1557,6 +1573,7 @@ class FluidSimulation bool _isMarkerParticleLoadPending = false; bool _isDiffuseParticleLoadPending = false; std::vector _markerParticleLoadQueue; + std::vector _markerParticleAffineLoadQueue; std::vector _diffuseParticleLoadQueue; // Update obstacles @@ -1626,6 +1643,7 @@ class FluidSimulation VelocityAdvector _velocityAdvector; int _maxParticlesPerVelocityAdvection = 5e6; std::thread _advectVelocityFieldThread; + VelocityTransferMethod _velocityTransferMethod = VelocityTransferMethod::FLIP; // Calculate fluid curvature Array3d _fluidSurfaceLevelSet; @@ -1641,9 +1659,11 @@ class FluidSimulation ForceFieldGrid _forceFieldGrid; // Viscosity solve + ViscositySolver _viscositySolver; Array3d _viscosity; bool _isViscosityEnabled = false; double _constantViscosityValue = 0.0; + double _viscositySolverErrorTolerance = 1e-4; std::string _viscositySolverStatus; // Pressure solve @@ -1675,20 +1695,21 @@ class FluidSimulation // Update MarkerParticle velocities int _maxParticlesPerPICFLIPUpdate = 10e6; double _ratioPICFLIP = 0.05; + double _ratioPICAPIC = 0.00; MACVelocityField _MACVelocity; MACVelocityField _savedVelocityField; // Advance MarkerParticles int _maxParticlesPerParticleAdvection = 10e6; int _maxMarkerParticlesPerCell = 250; - float _solidBufferWidth = 0.1f; + float _solidBufferWidth = 0.2f; bool _isAdaptiveObstacleTimeSteppingEnabled = false; bool _isAdaptiveForceFieldTimeSteppingEnabled = false; bool _isExtremeVelocityRemovalEnabled = true; double _maxExtremeVelocityRemovalPercent = 0.0005; int _maxExtremeVelocityRemovalAbsolute = 35; int _minTimeStepIncreaseForRemoval = 4; - float _markerParticleStepDistanceFactor = 0.5; + float _markerParticleStepDistanceFactor = 0.1f; // OpenCL // NOTE: These objects are not used within the simulator, but will remain diff --git a/src/engine/forcefield.cpp b/src/engine/forcefield.cpp index 38a151cd..257585a3 100644 --- a/src/engine/forcefield.cpp +++ b/src/engine/forcefield.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/forcefield.h b/src/engine/forcefield.h index d2997edc..e793cc21 100644 --- a/src/engine/forcefield.h +++ b/src/engine/forcefield.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/forcefieldcurve.cpp b/src/engine/forcefieldcurve.cpp index 51c0893b..139ba511 100644 --- a/src/engine/forcefieldcurve.cpp +++ b/src/engine/forcefieldcurve.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/forcefieldcurve.h b/src/engine/forcefieldcurve.h index f272e34b..59b46304 100644 --- a/src/engine/forcefieldcurve.h +++ b/src/engine/forcefieldcurve.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/forcefieldgravityscalegrid.h b/src/engine/forcefieldgravityscalegrid.h index a37f5db6..88671356 100644 --- a/src/engine/forcefieldgravityscalegrid.h +++ b/src/engine/forcefieldgravityscalegrid.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/forcefieldgrid.cpp b/src/engine/forcefieldgrid.cpp index 0737a5da..5ed8199b 100644 --- a/src/engine/forcefieldgrid.cpp +++ b/src/engine/forcefieldgrid.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/forcefieldgrid.h b/src/engine/forcefieldgrid.h index ff122072..d3a683c7 100644 --- a/src/engine/forcefieldgrid.h +++ b/src/engine/forcefieldgrid.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/forcefieldpoint.cpp b/src/engine/forcefieldpoint.cpp index dafdbdd2..7444a7b3 100644 --- a/src/engine/forcefieldpoint.cpp +++ b/src/engine/forcefieldpoint.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/forcefieldpoint.h b/src/engine/forcefieldpoint.h index d271b5de..f62b9b94 100644 --- a/src/engine/forcefieldpoint.h +++ b/src/engine/forcefieldpoint.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/forcefieldsurface.cpp b/src/engine/forcefieldsurface.cpp index 0ff03382..6f4f6778 100644 --- a/src/engine/forcefieldsurface.cpp +++ b/src/engine/forcefieldsurface.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/forcefieldsurface.h b/src/engine/forcefieldsurface.h index 83650ca2..31dbe703 100644 --- a/src/engine/forcefieldsurface.h +++ b/src/engine/forcefieldsurface.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/forcefieldutils.cpp b/src/engine/forcefieldutils.cpp index 881e61d8..ed86ded8 100644 --- a/src/engine/forcefieldutils.cpp +++ b/src/engine/forcefieldutils.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/forcefieldutils.h b/src/engine/forcefieldutils.h index f470c8f2..e6db7691 100644 --- a/src/engine/forcefieldutils.h +++ b/src/engine/forcefieldutils.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/forcefieldvolume.cpp b/src/engine/forcefieldvolume.cpp index 42854561..6a1a57eb 100644 --- a/src/engine/forcefieldvolume.cpp +++ b/src/engine/forcefieldvolume.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/forcefieldvolume.h b/src/engine/forcefieldvolume.h index c7ac03a1..915bae1e 100644 --- a/src/engine/forcefieldvolume.h +++ b/src/engine/forcefieldvolume.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/fragmentedvector.h b/src/engine/fragmentedvector.h index 502dde48..d558ac38 100644 --- a/src/engine/fragmentedvector.h +++ b/src/engine/fragmentedvector.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/grid3d.h b/src/engine/grid3d.h index e182c230..c12934b5 100644 --- a/src/engine/grid3d.h +++ b/src/engine/grid3d.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/gridindexkeymap.cpp b/src/engine/gridindexkeymap.cpp index 06e09095..42872d08 100644 --- a/src/engine/gridindexkeymap.cpp +++ b/src/engine/gridindexkeymap.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/gridindexkeymap.h b/src/engine/gridindexkeymap.h index bab24bfa..0c7f5289 100644 --- a/src/engine/gridindexkeymap.h +++ b/src/engine/gridindexkeymap.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/gridindexvector.cpp b/src/engine/gridindexvector.cpp index 02dde70f..26d1ae89 100644 --- a/src/engine/gridindexvector.cpp +++ b/src/engine/gridindexvector.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/gridindexvector.h b/src/engine/gridindexvector.h index 2ac03613..e53fe3b5 100644 --- a/src/engine/gridindexvector.h +++ b/src/engine/gridindexvector.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/gridutils.cpp b/src/engine/gridutils.cpp index c56bf2cc..0c1bf155 100644 --- a/src/engine/gridutils.cpp +++ b/src/engine/gridutils.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/gridutils.h b/src/engine/gridutils.h index 8078e51d..9e38efe2 100644 --- a/src/engine/gridutils.h +++ b/src/engine/gridutils.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/influencegrid.cpp b/src/engine/influencegrid.cpp index 7997076e..96f4a9e9 100644 --- a/src/engine/influencegrid.cpp +++ b/src/engine/influencegrid.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/influencegrid.h b/src/engine/influencegrid.h index f611ec67..cc8d16f8 100644 --- a/src/engine/influencegrid.h +++ b/src/engine/influencegrid.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/interpolation.cpp b/src/engine/interpolation.cpp index 377dc26c..e35a66b2 100644 --- a/src/engine/interpolation.cpp +++ b/src/engine/interpolation.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/interpolation.h b/src/engine/interpolation.h index 0564fd52..33aa5d51 100644 --- a/src/engine/interpolation.h +++ b/src/engine/interpolation.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/kernels/kernels.cpp.in b/src/engine/kernels/kernels.cpp.in index 67cf5c52..65ac8706 100644 --- a/src/engine/kernels/kernels.cpp.in +++ b/src/engine/kernels/kernels.cpp.in @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/kernels/kernels.h b/src/engine/kernels/kernels.h index 82b5219c..fd3cd97b 100644 --- a/src/engine/kernels/kernels.h +++ b/src/engine/kernels/kernels.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/kernels/scalarfield.cl b/src/engine/kernels/scalarfield.cl index 7b207374..9b1204c1 100644 --- a/src/engine/kernels/scalarfield.cl +++ b/src/engine/kernels/scalarfield.cl @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/kernels/trilinearinterpolate.cl b/src/engine/kernels/trilinearinterpolate.cl index 5635e011..fa3ce628 100644 --- a/src/engine/kernels/trilinearinterpolate.cl +++ b/src/engine/kernels/trilinearinterpolate.cl @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/levelsetsolver.cpp b/src/engine/levelsetsolver.cpp index 7a22203d..76e2bfbf 100644 --- a/src/engine/levelsetsolver.cpp +++ b/src/engine/levelsetsolver.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/levelsetsolver.h b/src/engine/levelsetsolver.h index 37589ba4..f6040f7a 100644 --- a/src/engine/levelsetsolver.h +++ b/src/engine/levelsetsolver.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/levelsetutils.cpp b/src/engine/levelsetutils.cpp index d0568169..a0f7b8a0 100644 --- a/src/engine/levelsetutils.cpp +++ b/src/engine/levelsetutils.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/levelsetutils.h b/src/engine/levelsetutils.h index a88ad2ab..3701c13b 100644 --- a/src/engine/levelsetutils.h +++ b/src/engine/levelsetutils.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/logfile.cpp b/src/engine/logfile.cpp index a16ad51f..1ae5fe58 100644 --- a/src/engine/logfile.cpp +++ b/src/engine/logfile.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/logfile.h b/src/engine/logfile.h index 5c45b255..6feb1c47 100644 --- a/src/engine/logfile.h +++ b/src/engine/logfile.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/macvelocityfield.cpp b/src/engine/macvelocityfield.cpp index 159535b5..99d2165e 100644 --- a/src/engine/macvelocityfield.cpp +++ b/src/engine/macvelocityfield.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/macvelocityfield.h b/src/engine/macvelocityfield.h index d5d66d06..d45f170a 100644 --- a/src/engine/macvelocityfield.h +++ b/src/engine/macvelocityfield.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/main.cpp b/src/engine/main.cpp index 46d80b09..68e6153d 100644 --- a/src/engine/main.cpp +++ b/src/engine/main.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -67,6 +67,7 @@ TriangleMesh getTriangleMeshFromAABB(AABB bbox) { } int main() { + // This example will drop a box of fluid in the center // of the fluid simulation domain. int isize = 64; diff --git a/src/engine/markerparticle.h b/src/engine/markerparticle.h index c28bf86f..bbe646ba 100644 --- a/src/engine/markerparticle.h +++ b/src/engine/markerparticle.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -42,4 +42,15 @@ struct MarkerParticle { position(x, y, z) {} }; +struct MarkerParticleAffine { + vmath::vec3 affineX; + vmath::vec3 affineY; + vmath::vec3 affineZ; + + MarkerParticleAffine(vmath::vec3 ax, vmath::vec3 ay, vmath::vec3 az) : + affineX(ax), + affineY(ay), + affineZ(az) {} +}; + #endif \ No newline at end of file diff --git a/src/engine/meshfluidsource.cpp b/src/engine/meshfluidsource.cpp index 514cf32c..7ccb32f5 100644 --- a/src/engine/meshfluidsource.cpp +++ b/src/engine/meshfluidsource.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/meshfluidsource.h b/src/engine/meshfluidsource.h index 2323d832..d1e1f576 100644 --- a/src/engine/meshfluidsource.h +++ b/src/engine/meshfluidsource.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/meshlevelset.cpp b/src/engine/meshlevelset.cpp index 482b673d..358e49df 100644 --- a/src/engine/meshlevelset.cpp +++ b/src/engine/meshlevelset.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/meshlevelset.h b/src/engine/meshlevelset.h index a3844f4b..99ca40f4 100644 --- a/src/engine/meshlevelset.h +++ b/src/engine/meshlevelset.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/meshobject.cpp b/src/engine/meshobject.cpp index cd14c922..e6bcf64d 100644 --- a/src/engine/meshobject.cpp +++ b/src/engine/meshobject.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/meshobject.h b/src/engine/meshobject.h index 6e287690..2feb9492 100644 --- a/src/engine/meshobject.h +++ b/src/engine/meshobject.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/meshutils.cpp b/src/engine/meshutils.cpp index 9a7e537d..09adbfdf 100644 --- a/src/engine/meshutils.cpp +++ b/src/engine/meshutils.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/meshutils.h b/src/engine/meshutils.h index b92f03d2..0f7d4007 100644 --- a/src/engine/meshutils.h +++ b/src/engine/meshutils.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/noisegenerationutils.cpp b/src/engine/noisegenerationutils.cpp index 1f7dac64..f30409d0 100644 --- a/src/engine/noisegenerationutils.cpp +++ b/src/engine/noisegenerationutils.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/noisegenerationutils.h b/src/engine/noisegenerationutils.h index 1c40fbcc..7df3c943 100644 --- a/src/engine/noisegenerationutils.h +++ b/src/engine/noisegenerationutils.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/opencl_bindings/clcpp.cpp b/src/engine/opencl_bindings/clcpp.cpp index c7b7474b..bed2f78c 100644 --- a/src/engine/opencl_bindings/clcpp.cpp +++ b/src/engine/opencl_bindings/clcpp.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/opencl_bindings/clcpp.h b/src/engine/opencl_bindings/clcpp.h index d83ed63e..991f270d 100644 --- a/src/engine/opencl_bindings/clcpp.h +++ b/src/engine/opencl_bindings/clcpp.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/openclutils.cpp b/src/engine/openclutils.cpp index 8693695a..da15b4ce 100644 --- a/src/engine/openclutils.cpp +++ b/src/engine/openclutils.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/openclutils.h b/src/engine/openclutils.h index 3bb8d223..c36f6dea 100644 --- a/src/engine/openclutils.h +++ b/src/engine/openclutils.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/particleadvector.cpp b/src/engine/particleadvector.cpp index 2beaaead..ea7be5c7 100644 --- a/src/engine/particleadvector.cpp +++ b/src/engine/particleadvector.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/particleadvector.h b/src/engine/particleadvector.h index 18b7335e..9a2ed8c6 100644 --- a/src/engine/particleadvector.h +++ b/src/engine/particleadvector.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/particlelevelset.cpp b/src/engine/particlelevelset.cpp index 502529e3..041c12fb 100644 --- a/src/engine/particlelevelset.cpp +++ b/src/engine/particlelevelset.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -158,14 +158,12 @@ float ParticleLevelSet::getDistanceAtNode(GridIndex g) { return getDistanceAtNode(g.i, g.j, g.k); } -void ParticleLevelSet::calculateSignedDistanceField(FragmentedVector &particles, +void ParticleLevelSet::calculateSignedDistanceField(ParticleSystem &particles, double radius) { - std::vector points; - points.reserve(particles.size()); - for (size_t i = 0; i < particles.size(); i++) { - points.push_back(particles[i].position); - } + std::vector *positions; + particles.getAttributeValues("POSITION", positions); + std::vector points = *positions; _computeSignedDistanceFromParticles(points, radius); } diff --git a/src/engine/particlelevelset.h b/src/engine/particlelevelset.h index 36283fcf..9691f977 100644 --- a/src/engine/particlelevelset.h +++ b/src/engine/particlelevelset.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -36,6 +36,7 @@ SOFTWARE. #include "vmath.h" #include "blockarray3d.h" #include "boundedbuffer.h" +#include "particlesystem.h" class MeshLevelSet; class ScalarField; @@ -63,7 +64,7 @@ class ParticleLevelSet { float getDistanceAtNode(int i, int j, int k); float getDistanceAtNode(GridIndex g); - void calculateSignedDistanceField(FragmentedVector &particles, + void calculateSignedDistanceField(ParticleSystem &particles, double radius); void postProcessSignedDistanceField(MeshLevelSet &solidPhi); void calculateCurvatureGrid(Array3d &surfacePhi, Array3d &kgrid); diff --git a/src/engine/particlemaskgrid.cpp b/src/engine/particlemaskgrid.cpp index c20068a0..9aeade24 100644 --- a/src/engine/particlemaskgrid.cpp +++ b/src/engine/particlemaskgrid.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/particlemaskgrid.h b/src/engine/particlemaskgrid.h index 50dde861..4b9aa7c4 100644 --- a/src/engine/particlemaskgrid.h +++ b/src/engine/particlemaskgrid.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/particlemesher.cpp b/src/engine/particlemesher.cpp index 65a30d0d..125d8c1b 100644 --- a/src/engine/particlemesher.cpp +++ b/src/engine/particlemesher.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/particlemesher.h b/src/engine/particlemesher.h index f5bdd55f..38d397bd 100644 --- a/src/engine/particlemesher.h +++ b/src/engine/particlemesher.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/particlesheeter.cpp b/src/engine/particlesheeter.cpp index 9947969d..d3aa2a44 100644 --- a/src/engine/particlesheeter.cpp +++ b/src/engine/particlesheeter.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -85,8 +85,11 @@ void ParticleSheeter::_initializeParameters(ParticleSheeterParameters params) { } void ParticleSheeter::_getMarkerParticleCellCounts(Array3d &countGrid) { - for (size_t i = 0; i < _particles->size(); i++) { - vmath::vec3 p = _particles->at(i).position; + std::vector *positions; + _particles->getAttributeValues("POSITION", positions); + + for (size_t i = 0; i < positions->size(); i++) { + vmath::vec3 p = positions->at(i); GridIndex g = Grid3d::positionToGridIndex(p, _dx); if ((int)(countGrid(g)) == 255) { continue; @@ -122,8 +125,11 @@ void ParticleSheeter::_identifySheetParticlesPhase1Thread(int startidx, int endi float eps = 1e-5; vmath::vec3 hdx(0.5*_dx, 0.5*_dx, 0.5*_dx); + std::vector *positions; + _particles->getAttributeValues("POSITION", positions); + for (int i = startidx; i < endidx; i++) { - vmath::vec3 p = _particles->at(i).position; + vmath::vec3 p = positions->at(i); GridIndex g = Grid3d::positionToGridIndex(p, _dx); if ((int)(countGrid->get(g)) >= _maxParticlesPerCell) { // too dense to be a sheet that needs reseeding @@ -247,10 +253,13 @@ void ParticleSheeter::_identifySheetParticlesPhase2Thread(int startidx, int endi Array3d *sheetCells, Array3d *countGrid, std::vector *result) { + std::vector *positions; + _particles->getAttributeValues("POSITION", positions); + vmath::vec3 hdx(0.5*_dx, 0.5*_dx, 0.5*_dx); float maxdepth = _maxSheetDepth * _dx; for (int i = startidx; i < endidx; i++) { - vmath::vec3 p = _particles->at(i).position; + vmath::vec3 p = positions->at(i); GridIndex g = Grid3d::positionToGridIndex(p, _dx); if (!sheetCells->get(g)) { continue; @@ -275,8 +284,11 @@ void ParticleSheeter::_identifySheetParticlesPhase2Thread(int startidx, int endi } void ParticleSheeter::_initializeMaskGrid(ParticleMaskGrid &maskgrid) { - for (size_t i = 0; i < _particles->size(); i++) { - maskgrid.addParticle(_particles->at(i).position); + std::vector *positions; + _particles->getAttributeValues("POSITION", positions); + + for (size_t i = 0; i < positions->size(); i++) { + maskgrid.addParticle(positions->at(i)); } } diff --git a/src/engine/particlesheeter.h b/src/engine/particlesheeter.h index e98b758a..d1a21828 100644 --- a/src/engine/particlesheeter.h +++ b/src/engine/particlesheeter.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -30,10 +30,11 @@ SOFTWARE. #include "meshlevelset.h" #include "particlemaskgrid.h" #include "vmath.h" +#include "particlesystem.h" struct ParticleSheeterParameters { - FragmentedVector *particles; + ParticleSystem *particles; Array3d *fluidSurfaceLevelSet; int isize = 0; @@ -118,7 +119,7 @@ class ParticleSheeter { std::vector *result); // External parameters - FragmentedVector *_particles; + ParticleSystem *_particles; Array3d *_fluidSurfaceLevelSet; int _isize = 0; diff --git a/src/engine/particlesystem.cpp b/src/engine/particlesystem.cpp new file mode 100644 index 00000000..6eb13194 --- /dev/null +++ b/src/engine/particlesystem.cpp @@ -0,0 +1,523 @@ +/* +MIT License + +Copyright (C) 2020 Ryan L. Guy + +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. +*/ + +#include "particlesystem.h" + + +ParticleSystem::ParticleSystem() { +} + +void ParticleSystem::update() { + size_t size = evaluateSize(); + _expandVectors(_charAttributes, _charDefaults, size); + _expandVectors(_ucharAttributes, _ucharDefaults, size); + _expandVectors(_boolAttributes, _boolDefaults, size); + _expandVectors(_intAttributes, _intDefaults, size); + _expandVectors(_idAttributes, _idDefaults, size); + _expandVectors(_floatAttributes, _floatDefaults, size); + _expandVectors(_vector3Attributes, _vector3Defaults, size); + _size = size; +} + +size_t ParticleSystem::evaluateSize() { + size_t size = 0; + size = std::max(size, _getMaxVectorSize(_charAttributes)); + size = std::max(size, _getMaxVectorSize(_ucharAttributes)); + size = std::max(size, _getMaxVectorSize(_boolAttributes)); + size = std::max(size, _getMaxVectorSize(_intAttributes)); + size = std::max(size, _getMaxVectorSize(_idAttributes)); + size = std::max(size, _getMaxVectorSize(_floatAttributes)); + size = std::max(size, _getMaxVectorSize(_vector3Attributes)); + return size; +} + +bool ParticleSystem::empty() { + return evaluateSize() == 0; +} + +void ParticleSystem::resize(size_t n) { + _resizeVectors(_charAttributes, n); + _resizeVectors(_ucharAttributes, n); + _resizeVectors(_boolAttributes, n); + _resizeVectors(_intAttributes, n); + _resizeVectors(_idAttributes, n); + _resizeVectors(_floatAttributes, n); + _resizeVectors(_vector3Attributes, n); + update(); +} + +void ParticleSystem::reserve(size_t n) { + _reserveVectors(_charAttributes, n); + _reserveVectors(_ucharAttributes, n); + _reserveVectors(_boolAttributes, n); + _reserveVectors(_intAttributes, n); + _reserveVectors(_idAttributes, n); + _reserveVectors(_floatAttributes, n); + _reserveVectors(_vector3Attributes, n); +} + +void ParticleSystem::removeParticles(std::vector &toRemove) { + _removeParticlesFromVectorList(_charAttributes, toRemove); + _removeParticlesFromVectorList(_ucharAttributes, toRemove); + _removeParticlesFromVectorList(_boolAttributes, toRemove); + _removeParticlesFromVectorList(_intAttributes, toRemove); + _removeParticlesFromVectorList(_idAttributes, toRemove); + _removeParticlesFromVectorList(_floatAttributes, toRemove); + _removeParticlesFromVectorList(_vector3Attributes, toRemove); + update(); +} + +void ParticleSystem::printParticle(size_t index) { + for (size_t aidx = 0; aidx < _attributes.size(); aidx++) { + ParticleSystemAttribute att = _attributes[aidx]; + + switch (att.type) { + case AttributeDataType::CHAR: + { + char value = _charAttributes[att.id][index]; + std::cout << att.name << " \t" << (int)value << std::endl; + break; + } + case AttributeDataType::UCHAR: + { + unsigned char value = _ucharAttributes[att.id][index]; + std::cout << att.name << " \t" << (int)value << std::endl; + break; + } + case AttributeDataType::BOOL: + { + bool value = _boolAttributes[att.id][index]; + std::cout << att.name << " \t" << value << std::endl; + break; + } + case AttributeDataType::INT: + { + int value = _intAttributes[att.id][index]; + std::cout << att.name << " \t" << value << std::endl; + break; + } + case AttributeDataType::ID: + { + size_t value = _idAttributes[att.id][index]; + std::cout << att.name << " \t" << value << std::endl; + break; + } + case AttributeDataType::FLOAT: + { + float value = _floatAttributes[att.id][index]; + std::cout << att.name << " \t" << value << std::endl; + break; + } + case AttributeDataType::VECTOR3: + { + vmath::vec3 value = _vector3Attributes[att.id][index]; + std::cout << att.name << " \t" << value << std::endl; + break; + } + default: + std::cout << "Error: Undefined Attribute \t" << att.name << std::endl; + break; + } + } +} + +bool ParticleSystem::isSchemaEqual(ParticleSystem &other, bool strict) { + std::vector otherAttributes = other.getAttributes(); + if (this->_attributes.size() != otherAttributes.size()) { + return false; + } + + for (size_t i = 0; i < _attributes.size(); i++) { + if (strict) { + if (_attributes[i] != otherAttributes[i]) { + return false; + } + } else { + ParticleSystemAttribute thisAtt = _attributes[i]; + ParticleSystemAttribute otherAtt = other.getAttribute(thisAtt.name); + if (thisAtt.name != otherAtt.name || thisAtt.type != otherAtt.type) { + return false; + } + } + } + + for (size_t i = 0; i < _attributes.size(); i++) { + ParticleSystemAttribute thisAtt = _attributes[i]; + ParticleSystemAttribute otherAtt = other.getAttribute(thisAtt.name); + + float eps = 1e-6; + switch (thisAtt.type) { + case AttributeDataType::CHAR: + { + char *thisDefault, *otherDefault; + getAttributeDefault(thisAtt, thisDefault); + other.getAttributeDefault(otherAtt, otherDefault); + if (*thisDefault != *otherDefault) { + return false; + } + break; + } + case AttributeDataType::UCHAR: + { + unsigned char *thisDefault, *otherDefault; + getAttributeDefault(thisAtt, thisDefault); + other.getAttributeDefault(otherAtt, otherDefault); + if (*thisDefault != *otherDefault) { + return false; + } + break; + } + case AttributeDataType::BOOL: + { + bool *thisDefault, *otherDefault; + getAttributeDefault(thisAtt, thisDefault); + other.getAttributeDefault(otherAtt, otherDefault); + if (*thisDefault != *otherDefault) { + return false; + } + break; + } + case AttributeDataType::INT: + { + int *thisDefault, *otherDefault; + getAttributeDefault(thisAtt, thisDefault); + other.getAttributeDefault(otherAtt, otherDefault); + if (*thisDefault != *otherDefault) { + return false; + } + break; + } + case AttributeDataType::ID: + { + size_t *thisDefault, *otherDefault; + getAttributeDefault(thisAtt, thisDefault); + other.getAttributeDefault(otherAtt, otherDefault); + if (*thisDefault != *otherDefault) { + return false; + } + break; + } + case AttributeDataType::FLOAT: + { + float *thisDefault, *otherDefault; + getAttributeDefault(thisAtt, thisDefault); + other.getAttributeDefault(otherAtt, otherDefault); + if (std::abs(*thisDefault - *otherDefault) > eps) { + return false; + } + break; + } + case AttributeDataType::VECTOR3: + { + vmath::vec3 *thisDefault, *otherDefault; + getAttributeDefault(thisAtt, thisDefault); + other.getAttributeDefault(otherAtt, otherDefault); + if (vmath::length(*thisDefault - *otherDefault) > eps) { + return false; + } + break; + } + default: + { + break; + } + } + + } + + return true; +} + +ParticleSystem ParticleSystem::generateEmptyCopy() { + ParticleSystem newSystem; + + for (size_t i = 0; i < _attributes.size(); i++) { + ParticleSystemAttribute att = _attributes[i]; + + switch (att.type) { + case AttributeDataType::CHAR: + { + char *def; + getAttributeDefault(att, def); + newSystem.addAttributeChar(att.name, *def); + break; + } + case AttributeDataType::UCHAR: + { + unsigned char *def; + getAttributeDefault(att, def); + newSystem.addAttributeUChar(att.name, *def); + break; + } + case AttributeDataType::BOOL: + { + bool *def; + getAttributeDefault(att, def); + newSystem.addAttributeBool(att.name, *def); + break; + } + case AttributeDataType::INT: + { + int *def; + getAttributeDefault(att, def); + newSystem.addAttributeInt(att.name, *def); + break; + } + case AttributeDataType::ID: + { + size_t *def; + getAttributeDefault(att, def); + newSystem.addAttributeID(att.name, *def); + break; + } + case AttributeDataType::FLOAT: + { + float *def; + getAttributeDefault(att, def); + newSystem.addAttributeFloat(att.name, *def); + break; + } + case AttributeDataType::VECTOR3: + { + vmath::vec3 *def; + getAttributeDefault(att, def); + newSystem.addAttributeVector3(att.name, *def); + break; + } + default: + { + std::string msg = "Error: Invalid ParticleSystemAttribute in generateEmptyCopy()"; + msg += " \n"; + throw std::runtime_error(msg); + break; + } + } + } + + return newSystem; +} + +void ParticleSystem::merge(ParticleSystem &other) { + FLUIDSIM_ASSERT(isSchemaEqual(other)); + + update(); + other.update(); + _mergeVectors(_charAttributes, other._charAttributes); + _mergeVectors(_ucharAttributes, other._ucharAttributes); + _mergeVectors(_boolAttributes, other._boolAttributes); + _mergeVectors(_intAttributes, other._intAttributes); + _mergeVectors(_idAttributes, other._idAttributes); + _mergeVectors(_floatAttributes, other._floatAttributes); + _mergeVectors(_vector3Attributes, other._vector3Attributes); + update(); +} + +ParticleSystemAttribute ParticleSystem::addAttributeChar(std::string name, char defaultValue) { + ParticleSystemAttribute att; + att.id = _charAttributes.size(); + att.name = name; + att.type = AttributeDataType::CHAR; + + _attributes.push_back(att); + _charAttributes.push_back(std::vector()); + _charDefaults.push_back(defaultValue); + + return att; +} + +ParticleSystemAttribute ParticleSystem::addAttributeUChar(std::string name, unsigned char defaultValue) { + ParticleSystemAttribute att; + att.id = _ucharAttributes.size(); + att.name = name; + att.type = AttributeDataType::UCHAR; + + _attributes.push_back(att); + _ucharAttributes.push_back(std::vector()); + _ucharDefaults.push_back(defaultValue); + + return att; +} + +ParticleSystemAttribute ParticleSystem::addAttributeBool(std::string name, bool defaultValue) { + ParticleSystemAttribute att; + att.id = _boolAttributes.size(); + att.name = name; + att.type = AttributeDataType::BOOL; + + _attributes.push_back(att); + _boolAttributes.push_back(std::vector()); + _boolDefaults.push_back(defaultValue); + + return att; +} + +ParticleSystemAttribute ParticleSystem::addAttributeInt(std::string name, int defaultValue) { + ParticleSystemAttribute att; + att.id = _intAttributes.size(); + att.name = name; + att.type = AttributeDataType::INT; + + _attributes.push_back(att); + _intAttributes.push_back(std::vector()); + _intDefaults.push_back(defaultValue); + + return att; +} + +ParticleSystemAttribute ParticleSystem::addAttributeID(std::string name, size_t defaultValue) { + ParticleSystemAttribute att; + att.id = _idAttributes.size(); + att.name = name; + att.type = AttributeDataType::ID; + + _attributes.push_back(att); + _idAttributes.push_back(std::vector()); + _idDefaults.push_back(defaultValue); + + return att; +} + +ParticleSystemAttribute ParticleSystem::addAttributeFloat(std::string name, float defaultValue) { + ParticleSystemAttribute att; + att.id = _floatAttributes.size(); + att.name = name; + att.type = AttributeDataType::FLOAT; + + _attributes.push_back(att); + _floatAttributes.push_back(std::vector()); + _floatDefaults.push_back(defaultValue); + + return att; +} + +ParticleSystemAttribute ParticleSystem::addAttributeVector3(std::string name, vmath::vec3 defaultValue) { + ParticleSystemAttribute att; + att.id = _vector3Attributes.size(); + att.name = name; + att.type = AttributeDataType::VECTOR3; + + _attributes.push_back(att); + _vector3Attributes.push_back(std::vector()); + _vector3Defaults.push_back(defaultValue); + + return att; +} + +std::vector *ParticleSystem::getAttributeValuesChar(ParticleSystemAttribute &att) { + _validateAttribute(att); + return &(_charAttributes[att.id]); +} + +std::vector *ParticleSystem::getAttributeValuesChar(std::string name) { + ParticleSystemAttribute att = _getAttributeByName(name); + return getAttributeValuesChar(att); +} + +std::vector *ParticleSystem::getAttributeValuesUChar(ParticleSystemAttribute &att) { + _validateAttribute(att); + return &(_ucharAttributes[att.id]); +} + +std::vector *ParticleSystem::getAttributeValuesUChar(std::string name) { + ParticleSystemAttribute att = _getAttributeByName(name); + return getAttributeValuesUChar(att); +} + +std::vector *ParticleSystem::getAttributeValuesBool(ParticleSystemAttribute &att) { + _validateAttribute(att); + return &(_boolAttributes[att.id]); +} + +std::vector *ParticleSystem::getAttributeValuesBool(std::string name) { + ParticleSystemAttribute att = _getAttributeByName(name); + return getAttributeValuesBool(att); +} + +std::vector *ParticleSystem::getAttributeValuesInt(ParticleSystemAttribute &att) { + _validateAttribute(att); + return &(_intAttributes[att.id]); +} + +std::vector *ParticleSystem::getAttributeValuesInt(std::string name) { + ParticleSystemAttribute att = _getAttributeByName(name); + return getAttributeValuesInt(att); +} + +std::vector *ParticleSystem::getAttributeValuesID(ParticleSystemAttribute &att) { + _validateAttribute(att); + return &(_idAttributes[att.id]); +} + +std::vector *ParticleSystem::getAttributeValuesID(std::string name) { + ParticleSystemAttribute att = _getAttributeByName(name); + return getAttributeValuesID(att); +} + +std::vector *ParticleSystem::getAttributeValuesFloat(ParticleSystemAttribute &att) { + _validateAttribute(att); + return &(_floatAttributes[att.id]); +} + +std::vector *ParticleSystem::getAttributeValuesFloat(std::string name) { + ParticleSystemAttribute att = _getAttributeByName(name); + return getAttributeValuesFloat(att); +} + +std::vector *ParticleSystem::getAttributeValuesVector3(ParticleSystemAttribute &att) { + _validateAttribute(att); + return &(_vector3Attributes[att.id]); +} + +std::vector *ParticleSystem::getAttributeValuesVector3(std::string name) { + ParticleSystemAttribute att = _getAttributeByName(name); + return getAttributeValuesVector3(att); +} + + +ParticleSystemAttribute ParticleSystem::_getAttributeByName(std::string name) { + for (size_t i = 0; i < _attributes.size(); i++) { + if (_attributes[i].name == name) { + return _attributes[i]; + } + } + + ParticleSystemAttribute blank; + blank.id = -1; + blank.name = name; + blank.type = AttributeDataType::UNDEFINED; + + return blank; +} + +void ParticleSystem::_validateAttribute(ParticleSystemAttribute &att) { + if (att.id < 0) { + std::string msg = "Error: Invalid ParticleSystemAttribute"; + msg += " \n"; + throw std::runtime_error(msg); + } +} \ No newline at end of file diff --git a/src/engine/particlesystem.h b/src/engine/particlesystem.h new file mode 100644 index 00000000..4441b7bd --- /dev/null +++ b/src/engine/particlesystem.h @@ -0,0 +1,314 @@ +/* +MIT License + +Copyright (C) 2020 Ryan L. Guy + +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. +*/ + +#ifndef FLUIDENGINE_PARTICLESYSTEM_H +#define FLUIDENGINE_PARTICLESYSTEM_H + +#include +#include +#include +#include + +#include "vmath.h" +#include "fluidsimassert.h" + + +enum class AttributeDataType : char { + UNDEFINED = 0x00, + CHAR = 0x01, + UCHAR = 0x02, + BOOL = 0x03, + INT = 0x04, + ID = 0x05, + FLOAT = 0x06, + VECTOR3 = 0x07 +}; + + +struct ParticleSystemAttribute { + int id = -1; + std::string name; + AttributeDataType type = AttributeDataType::UNDEFINED; + + bool operator== (const ParticleSystemAttribute &other) { + return id == other.id && name == other.name && type == other.type; + } + + bool operator!= (const ParticleSystemAttribute &other) { + return !(*this == other); + } +}; + + +class ParticleSystem +{ +public: + ParticleSystem(); + + void update(); + inline size_t size() { return _size; } + bool empty(); + size_t evaluateSize(); + void resize(size_t n); + void reserve(size_t n); + void removeParticles(std::vector &toRemove); + void printParticle(size_t index); + + std::vector getAttributes() { return _attributes; } + ParticleSystemAttribute getAttribute(std::string name) {return _getAttributeByName(name); } + bool isSchemaEqual(ParticleSystem &other, bool strict=true); + ParticleSystem generateEmptyCopy(); + void merge(ParticleSystem &other); + + ParticleSystemAttribute addAttributeChar(std::string name, char defaultValue=0x00); + ParticleSystemAttribute addAttributeUChar(std::string name, unsigned char defaultValue=0x00); + ParticleSystemAttribute addAttributeBool(std::string name, bool defaultValue=false); + ParticleSystemAttribute addAttributeInt(std::string name, int defaultValue=0); + ParticleSystemAttribute addAttributeID(std::string name, size_t defaultValue=-1); + ParticleSystemAttribute addAttributeFloat(std::string name, float defaultValue=0.0f); + ParticleSystemAttribute addAttributeVector3(std::string name, vmath::vec3 defaultValue=vmath::vec3()); + + std::vector *getAttributeValuesChar(ParticleSystemAttribute &att); + std::vector *getAttributeValuesChar(std::string name); + + std::vector *getAttributeValuesUChar(ParticleSystemAttribute &att); + std::vector *getAttributeValuesUChar(std::string name); + + std::vector *getAttributeValuesBool(ParticleSystemAttribute &att); + std::vector *getAttributeValuesBool(std::string name); + + std::vector *getAttributeValuesInt(ParticleSystemAttribute &att); + std::vector *getAttributeValuesInt(std::string name); + + std::vector *getAttributeValuesID(ParticleSystemAttribute &att); + std::vector *getAttributeValuesID(std::string name); + + std::vector *getAttributeValuesFloat(ParticleSystemAttribute &att); + std::vector *getAttributeValuesFloat(std::string name); + + std::vector *getAttributeValuesVector3(ParticleSystemAttribute &att); + std::vector *getAttributeValuesVector3(std::string name); + + template + void getAttributeValues(ParticleSystemAttribute &att, std::vector *&values) { + FLUIDSIM_ASSERT(att.type != AttributeDataType::UNDEFINED); + + switch (att.type) { + case AttributeDataType::CHAR: + values = (std::vector*)getAttributeValuesChar(att); + break; + case AttributeDataType::UCHAR: + values = (std::vector*)getAttributeValuesUChar(att); + break; + case AttributeDataType::BOOL: + values = (std::vector*)getAttributeValuesBool(att); + break; + case AttributeDataType::INT: + values = (std::vector*)getAttributeValuesInt(att); + break; + case AttributeDataType::ID: + values = (std::vector*)getAttributeValuesID(att); + break; + case AttributeDataType::FLOAT: + values = (std::vector*)getAttributeValuesFloat(att); + break; + case AttributeDataType::VECTOR3: + values = (std::vector*)getAttributeValuesVector3(att); + break; + default: + { + std::string msg = "Error: Invalid ParticleSystemAttribute in getAttributeValues()"; + msg += " \n"; + throw std::runtime_error(msg); + break; + } + } + } + + template + void getAttributeDefault(ParticleSystemAttribute &att, T *&value) { + FLUIDSIM_ASSERT(att.type != AttributeDataType::UNDEFINED); + + switch (att.type) { + case AttributeDataType::CHAR: + value = (T*)&(_charDefaults[att.id]); + break; + case AttributeDataType::UCHAR: + value = (T*)&(_ucharDefaults[att.id]); + break; + case AttributeDataType::BOOL: + value = _boolDefaults[att.id] ? (T*)&_boolValueTrue : (T*)&_boolValueFalse; + break; + case AttributeDataType::INT: + value = (T*)&(_intDefaults[att.id]); + break; + case AttributeDataType::ID: + value = (T*)&(_idDefaults[att.id]); + break; + case AttributeDataType::FLOAT: + value = (T*)&(_floatDefaults[att.id]); + break; + case AttributeDataType::VECTOR3: + value = (T*)&(_vector3Defaults[att.id]); + break; + default: + { + std::string msg = "Error: Invalid ParticleSystemAttribute in getAttributeDefault()"; + msg += " \n"; + throw std::runtime_error(msg); + break; + } + } + } + + template + void getAttributeValues(std::string name, std::vector *&values) { + ParticleSystemAttribute att = _getAttributeByName(name); + getAttributeValues(att, values); + } + + template + void addValues(ParticleSystemAttribute &att, std::vector &values) { + std::vector *thisAttribute; + getAttributeValues(att, thisAttribute); + thisAttribute->insert(thisAttribute->end(), values.begin(), values.end()); + } + + template + void addValues(std::string name, std::vector &values) { + ParticleSystemAttribute att = _getAttributeByName(name); + addValues(att, values); + } + +private: + + ParticleSystemAttribute _getAttributeByName(std::string name); + void _validateAttribute(ParticleSystemAttribute &att); + + template + std::string _toString(T item) { + std::ostringstream sstream; + sstream << item; + return sstream.str(); + } + + template + inline void _expandVectors(T1 &vectorList, T2 defaultList, size_t size) { + for (size_t i = 0; i < vectorList.size(); i++) { + if (vectorList[i].size() > size) { + return; + } + vectorList[i].resize(size, defaultList[i]); + } + } + + template + inline size_t _getMaxVectorSize(T &vectorList) { + size_t size = 0; + for (size_t i = 0; i < vectorList.size(); i++) { + size = std::max(size, vectorList[i].size()); + } + return size; + } + + template + inline void _resizeVectors(T &vectorList, size_t n) { + for (size_t i = 0; i < vectorList.size(); i++) { + vectorList[i].resize(n); + } + } + + template + inline void _reserveVectors(T &vectorList, size_t n) { + for (size_t i = 0; i < vectorList.size(); i++) { + vectorList[i].reserve(n); + } + } + + template + inline void _removeParticlesFromVector(T &vector, std::vector &toRemove) { + FLUIDSIM_ASSERT(vector.size() == toRemove.size()); + + int currentidx = 0; + for (size_t i = 0; i < vector.size(); i++) { + if (!toRemove[i]) { + vector[currentidx] = vector[i]; + currentidx++; + } + } + vector.resize(currentidx); + } + + template + inline void _removeParticlesFromVectorList(T &vectorList, std::vector &toRemove) { + for (size_t i = 0; i < vectorList.size(); i++) { + _removeParticlesFromVector(vectorList[i], toRemove); + } + } + + template + inline void _mergeVectors(T &vectorList1, T &vectorList2) { + for (size_t i = 0; i < vectorList1.size(); i++) { + vectorList1[i].insert(vectorList1[i].end(), vectorList2[i].begin(), vectorList2[i].end()); + } + } + + size_t _size = 0; + + std::vector _attributes; + + std::vector > _charAttributes; + std::vector > _ucharAttributes; + std::vector > _boolAttributes; + std::vector > _intAttributes; + std::vector > _idAttributes; + std::vector > _floatAttributes; + std::vector > _vector3Attributes; + + std::vector _charDefaults; + std::vector _ucharDefaults; + std::vector _boolDefaults; + std::vector _intDefaults; + std::vector _idDefaults; + std::vector _floatDefaults; + std::vector _vector3Defaults; + + std::string _defaultPositionName = "POSITION"; + std::string _defaultVelocityName = "VELOCITY"; + std::string _defaultDiffuseLifetimeName = "LIFETIME"; + std::string _defaultDiffuseTypeName = "TYPE"; + std::string _defaultDiffuseIDName = "ID"; + + // Workaround to get pointer to a true/false bool due to + // not being able to address an std::vector + bool _boolValueTrue = true; + bool _boolValueFalse = false; +}; + + +#endif \ No newline at end of file diff --git a/src/engine/pcgsolver/pcgsolver.h b/src/engine/pcgsolver/pcgsolver.h index 7d22a741..90f76d17 100644 --- a/src/engine/pcgsolver/pcgsolver.h +++ b/src/engine/pcgsolver/pcgsolver.h @@ -284,7 +284,7 @@ struct PCGSolver { BLAS::addScaled(-alpha, z, r); residualOut = BLAS::absMax(r); - if(residualOut <= tol) { + if(residualOut <= std::min(tol, (double)maxErrorTolerance)) { iterationsOut = iteration + 1; return true; } @@ -310,6 +310,7 @@ struct PCGSolver { // parameters T toleranceFactor; + T maxErrorTolerance = 1.0; int maxIterations; T modifiedIncompleteCholeskyParameter; T minDiagonalRatio; diff --git a/src/engine/polygonizer3d.cpp b/src/engine/polygonizer3d.cpp index c0367e66..f6b8bbf2 100644 --- a/src/engine/polygonizer3d.cpp +++ b/src/engine/polygonizer3d.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/polygonizer3d.h b/src/engine/polygonizer3d.h index d9d9ab4b..e23761ef 100644 --- a/src/engine/polygonizer3d.h +++ b/src/engine/polygonizer3d.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pressuresolver.cpp b/src/engine/pressuresolver.cpp index d0c6afb0..510be7c6 100644 --- a/src/engine/pressuresolver.cpp +++ b/src/engine/pressuresolver.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pressuresolver.h b/src/engine/pressuresolver.h index 310790be..99a8601c 100644 --- a/src/engine/pressuresolver.h +++ b/src/engine/pressuresolver.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pyfluid/__init__.py b/src/engine/pyfluid/__init__.py index 6a89314c..ead538c0 100644 --- a/src/engine/pyfluid/__init__.py +++ b/src/engine/pyfluid/__init__.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pyfluid/aabb.py b/src/engine/pyfluid/aabb.py index 3d32e12a..d737644f 100644 --- a/src/engine/pyfluid/aabb.py +++ b/src/engine/pyfluid/aabb.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pyfluid/array3d.py b/src/engine/pyfluid/array3d.py index 44d3196a..a2a694ae 100644 --- a/src/engine/pyfluid/array3d.py +++ b/src/engine/pyfluid/array3d.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pyfluid/fluidsimulation.py b/src/engine/pyfluid/fluidsimulation.py index 1671aa68..9d239f35 100644 --- a/src/engine/pyfluid/fluidsimulation.py +++ b/src/engine/pyfluid/fluidsimulation.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -1459,6 +1459,19 @@ def viscosity(self, value): pb.init_lib_func(libfunc, [c_void_p, c_double, c_void_p], None) pb.execute_lib_func(libfunc, [self(), value]) + @property + def viscosity_solver_error_tolerance(self): + libfunc = lib.FluidSimulation_get_viscosity_solver_error_tolerance + pb.init_lib_func(libfunc, [c_void_p, c_void_p], c_double) + return pb.execute_lib_func(libfunc, [self()]) + + @viscosity_solver_error_tolerance.setter + @decorators.check_ge_zero + def viscosity_solver_error_tolerance(self, value): + libfunc = lib.FluidSimulation_set_viscosity_solver_error_tolerance + pb.init_lib_func(libfunc, [c_void_p, c_double, c_void_p], None) + pb.execute_lib_func(libfunc, [self(), value]) + @property def surface_tension(self): libfunc = lib.FluidSimulation_get_surface_tension @@ -1626,6 +1639,26 @@ def enable_extreme_velocity_removal(self, boolval): pb.init_lib_func(libfunc, [c_void_p, c_void_p], None) pb.execute_lib_func(libfunc, [self()]) + def set_velocity_transfer_method_FLIP(self): + libfunc = lib.FluidSimulation_set_velocity_transfer_method_FLIP + pb.init_lib_func(libfunc, [c_void_p, c_void_p], None) + pb.execute_lib_func(libfunc, [self()]) + + def set_velocity_transfer_method_APIC(self): + libfunc = lib.FluidSimulation_set_velocity_transfer_method_APIC + pb.init_lib_func(libfunc, [c_void_p, c_void_p], None) + pb.execute_lib_func(libfunc, [self()]) + + def is_velocity_transfer_method_FLIP(self): + libfunc = lib.FluidSimulation_is_velocity_transfer_method_FLIP + pb.init_lib_func(libfunc, [c_void_p, c_void_p], c_int) + return bool(pb.execute_lib_func(libfunc, [self()])) + + def is_velocity_transfer_method_APIC(self): + libfunc = lib.FluidSimulation_is_velocity_transfer_method_APIC + pb.init_lib_func(libfunc, [c_void_p, c_void_p], c_int) + return bool(pb.execute_lib_func(libfunc, [self()])) + @property def PICFLIP_ratio(self): libfunc = lib.FluidSimulation_get_PICFLIP_ratio @@ -1640,6 +1673,20 @@ def PICFLIP_ratio(self, ratio): pb.init_lib_func(libfunc, [c_void_p, c_double, c_void_p], None) pb.execute_lib_func(libfunc, [self(), ratio]) + @property + def PICAPIC_ratio(self): + libfunc = lib.FluidSimulation_get_PICAPIC_ratio + pb.init_lib_func(libfunc, [c_void_p, c_void_p], c_double) + return pb.execute_lib_func(libfunc, [self()]) + + @PICAPIC_ratio.setter + @decorators.check_ge_zero + @decorators.check_le(1.0) + def PICAPIC_ratio(self, ratio): + libfunc = lib.FluidSimulation_set_PICAPIC_ratio + pb.init_lib_func(libfunc, [c_void_p, c_double, c_void_p], None) + pb.execute_lib_func(libfunc, [self(), ratio]) + @property def preferred_gpu_device(self): c_str = ctypes.create_string_buffer(4096) @@ -1770,19 +1817,6 @@ def get_num_diffuse_particles(self): pb.init_lib_func(libfunc, [c_void_p, c_void_p], c_int) return pb.execute_lib_func(libfunc, [self()]) - def get_diffuse_particles(self, startidx = None, endidx = None): - nparticles = self.get_num_diffuse_particles() - startidx, endidx = self._check_range(startidx, endidx, 0, nparticles) - n = endidx - startidx - out = (DiffuseParticle_t * n)() - - libfunc = lib.FluidSimulation_get_diffuse_particles - pb.init_lib_func(libfunc, - [c_void_p, c_int, c_int, c_void_p, c_void_p], None) - pb.execute_lib_func(libfunc, [self(), startidx, endidx, out]) - - return out - def get_diffuse_particle_positions(self, startidx = None, endidx = None): nparticles = self.get_num_diffuse_particles() startidx, endidx = self._check_range(startidx, endidx, 0, nparticles) @@ -1965,6 +1999,21 @@ def get_marker_particle_velocity_data_range(self, start_idx, end_idx): return self._get_output_data_range(lib.FluidSimulation_get_marker_particle_velocity_data_range, start_idx, end_idx, size_of_vector) + def get_marker_particle_affinex_data_range(self, start_idx, end_idx): + size_of_vector = 12 + return self._get_output_data_range(lib.FluidSimulation_get_marker_particle_affinex_data_range, + start_idx, end_idx, size_of_vector) + + def get_marker_particle_affiney_data_range(self, start_idx, end_idx): + size_of_vector = 12 + return self._get_output_data_range(lib.FluidSimulation_get_marker_particle_affiney_data_range, + start_idx, end_idx, size_of_vector) + + def get_marker_particle_affinez_data_range(self, start_idx, end_idx): + size_of_vector = 12 + return self._get_output_data_range(lib.FluidSimulation_get_marker_particle_affinez_data_range, + start_idx, end_idx, size_of_vector) + def get_diffuse_particle_position_data_range(self, start_idx, end_idx): size_of_vector = 12 return self._get_output_data_range(lib.FluidSimulation_get_diffuse_particle_position_data_range, @@ -2030,6 +2079,21 @@ def load_marker_particle_data(self, num_particles, position_data, velocity_data) pb.init_lib_func(libfunc, [c_void_p, FluidSimulationMarkerParticleData_t, c_void_p], None) pb.execute_lib_func(libfunc, [self(), pdata]) + def load_marker_particle_affine_data(self, num_particles, affinex_data, affiney_data, affinez_data): + c_affinex_data = (c_char * len(affinex_data)).from_buffer_copy(affinex_data) + c_affiney_data = (c_char * len(affiney_data)).from_buffer_copy(affiney_data) + c_affinez_data = (c_char * len(affinez_data)).from_buffer_copy(affinez_data) + + pdata = FluidSimulationMarkerParticleAffineData_t() + pdata.size = c_int(num_particles) + pdata.affinex = ctypes.cast(c_affinex_data, c_char_p) + pdata.affiney = ctypes.cast(c_affiney_data, c_char_p) + pdata.affinez = ctypes.cast(c_affinez_data, c_char_p) + + libfunc = lib.FluidSimulation_load_marker_particle_affine_data + pb.init_lib_func(libfunc, [c_void_p, FluidSimulationMarkerParticleAffineData_t, c_void_p], None) + pb.execute_lib_func(libfunc, [self(), pdata]) + def load_diffuse_particle_data(self, num_particles, position_data, velocity_data, lifetime_data, type_data, id_data): c_position_data = (c_char * len(position_data)).from_buffer_copy(position_data) @@ -2105,6 +2169,12 @@ class FluidSimulationMarkerParticleData_t(ctypes.Structure): ("positions", c_char_p), ("velocities", c_char_p)] +class FluidSimulationMarkerParticleAffineData_t(ctypes.Structure): + _fields_ = [("size", c_int), + ("affinex", c_char_p), + ("affiney", c_char_p), + ("affinez", c_char_p),] + class FluidSimulationDiffuseParticleData_t(ctypes.Structure): _fields_ = [("size", c_int), ("positions", c_char_p), diff --git a/src/engine/pyfluid/forcefield.py b/src/engine/pyfluid/forcefield.py index acbb3105..9d301f5a 100644 --- a/src/engine/pyfluid/forcefield.py +++ b/src/engine/pyfluid/forcefield.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pyfluid/forcefieldcurve.py b/src/engine/pyfluid/forcefieldcurve.py index dca5ef6a..59bc6f0a 100644 --- a/src/engine/pyfluid/forcefieldcurve.py +++ b/src/engine/pyfluid/forcefieldcurve.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pyfluid/forcefieldgrid.py b/src/engine/pyfluid/forcefieldgrid.py index 0d59c1f7..7a88f732 100644 --- a/src/engine/pyfluid/forcefieldgrid.py +++ b/src/engine/pyfluid/forcefieldgrid.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pyfluid/forcefieldpoint.py b/src/engine/pyfluid/forcefieldpoint.py index 66091196..cb764bd5 100644 --- a/src/engine/pyfluid/forcefieldpoint.py +++ b/src/engine/pyfluid/forcefieldpoint.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pyfluid/forcefieldsurface.py b/src/engine/pyfluid/forcefieldsurface.py index 5a7c2910..fd7318f3 100644 --- a/src/engine/pyfluid/forcefieldsurface.py +++ b/src/engine/pyfluid/forcefieldsurface.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pyfluid/forcefieldvolume.py b/src/engine/pyfluid/forcefieldvolume.py index e830bfb8..77d5f49f 100644 --- a/src/engine/pyfluid/forcefieldvolume.py +++ b/src/engine/pyfluid/forcefieldvolume.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pyfluid/gpu_utils.py b/src/engine/pyfluid/gpu_utils.py index 65502d89..6dc1aadd 100644 --- a/src/engine/pyfluid/gpu_utils.py +++ b/src/engine/pyfluid/gpu_utils.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pyfluid/gridindex.py b/src/engine/pyfluid/gridindex.py index 925ff482..e30c40a6 100644 --- a/src/engine/pyfluid/gridindex.py +++ b/src/engine/pyfluid/gridindex.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pyfluid/meshfluidsource.py b/src/engine/pyfluid/meshfluidsource.py index 4936386b..61ac4869 100644 --- a/src/engine/pyfluid/meshfluidsource.py +++ b/src/engine/pyfluid/meshfluidsource.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pyfluid/meshobject.py b/src/engine/pyfluid/meshobject.py index fd15ea4b..6308e5ff 100644 --- a/src/engine/pyfluid/meshobject.py +++ b/src/engine/pyfluid/meshobject.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pyfluid/method_decorators.py b/src/engine/pyfluid/method_decorators.py index 65b0f3cf..31e4d3f7 100644 --- a/src/engine/pyfluid/method_decorators.py +++ b/src/engine/pyfluid/method_decorators.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pyfluid/pybindings.py b/src/engine/pyfluid/pybindings.py index c9d281ed..47119365 100644 --- a/src/engine/pyfluid/pybindings.py +++ b/src/engine/pyfluid/pybindings.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/pyfluid/pyfluid.py b/src/engine/pyfluid/pyfluid.py index 94709745..53669740 100644 --- a/src/engine/pyfluid/pyfluid.py +++ b/src/engine/pyfluid/pyfluid.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -101,7 +101,7 @@ def _load_library(self, name): library = ctypes.cdll.LoadLibrary(libfile) IS_DEBUG_MODE_LIBRARY_LOADED = DEBUG_MODE_ENABLED except: - msg = "Unable to load fluid engine library: <" + libname + ">" + msg = "Unable to load fluid engine library: <" + libfile + ">" msg += " (1) Make sure that you are using a 64-bit version of Python/Blender" msg += " if built for 64-bit and likewise if built for 32-bit." msg += " (2) Try clearing your Blender user settings (make a backup first!)." diff --git a/src/engine/pyfluid/trianglemesh.py b/src/engine/pyfluid/trianglemesh.py index d7417b4b..b1086128 100644 --- a/src/engine/pyfluid/trianglemesh.py +++ b/src/engine/pyfluid/trianglemesh.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy +# Copyright (C) 2021 Ryan L. Guy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -65,9 +65,9 @@ def to_bobj(self): num_vertices = len(self.vertices) // 3 num_triangles = len(self.triangles) // 3 datastr = struct.pack('i', num_vertices) - datastr += self.vertices.tostring() + datastr += self.vertices.tobytes() datastr += struct.pack('i', num_triangles) - datastr += self.triangles.tostring() + datastr += self.triangles.tobytes() return datastr diff --git a/src/engine/pyfluid/vector3.py b/src/engine/pyfluid/vector3.py index a2b7e1f8..ff1be18f 100644 --- a/src/engine/pyfluid/vector3.py +++ b/src/engine/pyfluid/vector3.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (C) 2020 Ryan L. Guy, http://rlguy.com +# Copyright (C) 2021 Ryan L. Guy, http://rlguy.com # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/scalarfield.cpp b/src/engine/scalarfield.cpp index d00a1ac4..4918b8cf 100644 --- a/src/engine/scalarfield.cpp +++ b/src/engine/scalarfield.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/scalarfield.h b/src/engine/scalarfield.h index d516a7a4..03be8a53 100644 --- a/src/engine/scalarfield.h +++ b/src/engine/scalarfield.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/spatialpointgrid.cpp b/src/engine/spatialpointgrid.cpp index cb105602..2c50e0a5 100644 --- a/src/engine/spatialpointgrid.cpp +++ b/src/engine/spatialpointgrid.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/spatialpointgrid.h b/src/engine/spatialpointgrid.h index 1a86e120..3e65ccf6 100644 --- a/src/engine/spatialpointgrid.h +++ b/src/engine/spatialpointgrid.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/stopwatch.cpp b/src/engine/stopwatch.cpp index 063949c2..0bfe5740 100644 --- a/src/engine/stopwatch.cpp +++ b/src/engine/stopwatch.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/stopwatch.h b/src/engine/stopwatch.h index e603269e..32d12bee 100644 --- a/src/engine/stopwatch.h +++ b/src/engine/stopwatch.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/subdividedarray3d.h b/src/engine/subdividedarray3d.h index d13061ec..51db17e9 100644 --- a/src/engine/subdividedarray3d.h +++ b/src/engine/subdividedarray3d.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/threadutils.cpp b/src/engine/threadutils.cpp index 52b8db5e..9e97886e 100644 --- a/src/engine/threadutils.cpp +++ b/src/engine/threadutils.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/threadutils.h b/src/engine/threadutils.h index a2b26ee3..0ac9f32f 100644 --- a/src/engine/threadutils.h +++ b/src/engine/threadutils.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/triangle.h b/src/engine/triangle.h index 8019a9ab..51e9acfa 100644 --- a/src/engine/triangle.h +++ b/src/engine/triangle.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/trianglemesh.cpp b/src/engine/trianglemesh.cpp index cc32068d..9235c3e9 100644 --- a/src/engine/trianglemesh.cpp +++ b/src/engine/trianglemesh.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/trianglemesh.h b/src/engine/trianglemesh.h index 71184271..7bb7f356 100644 --- a/src/engine/trianglemesh.h +++ b/src/engine/trianglemesh.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/turbulencefield.cpp b/src/engine/turbulencefield.cpp index 8897973d..99f1b5ae 100644 --- a/src/engine/turbulencefield.cpp +++ b/src/engine/turbulencefield.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/turbulencefield.h b/src/engine/turbulencefield.h index b313c0d8..42bc2a8f 100644 --- a/src/engine/turbulencefield.h +++ b/src/engine/turbulencefield.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/velocityadvector.cpp b/src/engine/velocityadvector.cpp index 9ce9e489..65f706e2 100644 --- a/src/engine/velocityadvector.cpp +++ b/src/engine/velocityadvector.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -47,17 +47,27 @@ void VelocityAdvector::_initializeParameters(VelocityAdvectorParameters params) _vfield = params.vfield; _validVelocities = params.validVelocities; _particleRadius = params.particleRadius; + _velocityTransferMethod = params.velocityTransferMethod; _dx = _vfield->getGridCellSize(); _chunkdx = _dx * _chunkWidth; - _points.clear(); - _points.reserve(_particles->size()); - _velocities.clear(); - _velocities.reserve(_particles->size()); - for (size_t i = 0; i < _particles->size(); i++) { - _points.push_back((*_particles)[i].position); - _velocities.push_back((*_particles)[i].velocity); + std::vector *positions, *velocities; + _particles->getAttributeValues("POSITION", positions); + _particles->getAttributeValues("VELOCITY", velocities); + + _points = *positions; + _velocities = *velocities; + + if (_isAPIC()) { + std::vector *affineX, *affineY, *affineZ; + _particles->getAttributeValues("AFFINEX", affineX); + _particles->getAttributeValues("AFFINEY", affineY); + _particles->getAttributeValues("AFFINEZ", affineZ); + + _affineX = *affineX; + _affineY = *affineY; + _affineZ = *affineZ; } } @@ -69,8 +79,12 @@ void VelocityAdvector::_advectGrid(Direction dir) { _computeGridCountData(blockphi, gridCountData, dir); std::vector sortedParticleData; + std::vector sortedAffineData; std::vector blockToParticleDataIndex; - _sortParticlesIntoBlocks(gridCountData, sortedParticleData, blockToParticleDataIndex, dir); + _sortParticlesIntoBlocks(gridCountData, + sortedParticleData, sortedAffineData, + blockToParticleDataIndex, + dir); std::vector > gridBlocks; blockphi.getActiveGridBlocks(gridBlocks); @@ -86,6 +100,11 @@ void VelocityAdvector::_advectGrid(Direction dir) { ComputeBlock computeBlock; computeBlock.gridBlock = b; computeBlock.particleData = &(sortedParticleData[blockToParticleDataIndex[b.id]]); + + if (_isAPIC()) { + computeBlock.affineData = &(sortedAffineData[blockToParticleDataIndex[b.id]]); + } + computeBlock.numParticles = gridCountData.totalGridCount[b.id]; computeBlock.radius = _particleRadius; computeBlockQueue.push(computeBlock); @@ -96,8 +115,13 @@ void VelocityAdvector::_advectGrid(Direction dir) { int numthreads = (int)fmin(numCPU, std::ceil((float)computeBlockQueue.size() / (float)_numBlocksPerJob)); std::vector producerThreads(numthreads); for (int i = 0; i < numthreads; i++) { - producerThreads[i] = std::thread(&VelocityAdvector::_advectionProducerThread, this, + if (_isFLIP()) { + producerThreads[i] = std::thread(&VelocityAdvector::_advectionFLIPProducerThread, this, + &computeBlockQueue, &finishedComputeBlockQueue); + } else { + producerThreads[i] = std::thread(&VelocityAdvector::_advectionAPICProducerThread, this, &computeBlockQueue, &finishedComputeBlockQueue); + } } Array3d *vfieldgrid = NULL; @@ -330,6 +354,7 @@ void VelocityAdvector::_computeGridCountDataThread(int startidx, int endidx, void VelocityAdvector::_sortParticlesIntoBlocks(ParticleGridCountData &countdata, std::vector &sortedParticleData, + std::vector &sortedAffineData, std::vector &blockToParticleIndex, Direction dir) { int diridx = 0; @@ -352,43 +377,95 @@ void VelocityAdvector::_sortParticlesIntoBlocks(ParticleGridCountData &countdata vmath::vec3 offset = _getDirectionOffset(dir); sortedParticleData = std::vector(totalParticleCount); - for (int tidx = 0; tidx < countdata.numthreads; tidx++) { - GridCountData *countData = &(countdata.threadGridCountData[tidx]); - int indexOffset = countData->startidx; - int currentOverlappingIndex = 0; - for (size_t i = 0; i < countData->simpleGridIndices.size(); i++) { - if (countData->invalidPoints[i]) { - continue; + if (_isFLIP()) { + + for (int tidx = 0; tidx < countdata.numthreads; tidx++) { + GridCountData *countData = &(countdata.threadGridCountData[tidx]); + + int indexOffset = countData->startidx; + int currentOverlappingIndex = 0; + for (size_t i = 0; i < countData->simpleGridIndices.size(); i++) { + if (countData->invalidPoints[i]) { + continue; + } + + vmath::vec3 p = _points[i + indexOffset] - offset; + float v = _velocities[i + indexOffset][diridx]; + PointData pdata(p.x, p.y, p.z, v); + + if (countData->simpleGridIndices[i] >= 0) { + int blockid = countData->simpleGridIndices[i]; + int sortedIndex = blockToParticleIndexCurrent[blockid]; + sortedParticleData[sortedIndex] = pdata; + blockToParticleIndexCurrent[blockid]++; + } else { + int numblocks = -(countData->simpleGridIndices[i]); + for (int blockidx = 0; blockidx < numblocks; blockidx++) { + int blockid = countData->overlappingGridIndices[currentOverlappingIndex]; + currentOverlappingIndex++; + + int sortedIndex = blockToParticleIndexCurrent[blockid]; + sortedParticleData[sortedIndex] = pdata; + blockToParticleIndexCurrent[blockid]++; + } + } } + } - vmath::vec3 p = _points[i + indexOffset] - offset; - float v = _velocities[i + indexOffset][diridx]; - PointData pdata(p.x, p.y, p.z, v); + } else if (_isAPIC()) { - if (countData->simpleGridIndices[i] >= 0) { - int blockid = countData->simpleGridIndices[i]; - int sortedIndex = blockToParticleIndexCurrent[blockid]; - sortedParticleData[sortedIndex] = pdata; - blockToParticleIndexCurrent[blockid]++; - } else { - int numblocks = -(countData->simpleGridIndices[i]); - for (int blockidx = 0; blockidx < numblocks; blockidx++) { - int blockid = countData->overlappingGridIndices[currentOverlappingIndex]; - currentOverlappingIndex++; + sortedAffineData = std::vector(totalParticleCount); + for (int tidx = 0; tidx < countdata.numthreads; tidx++) { + GridCountData *countData = &(countdata.threadGridCountData[tidx]); + + int indexOffset = countData->startidx; + int currentOverlappingIndex = 0; + for (size_t i = 0; i < countData->simpleGridIndices.size(); i++) { + if (countData->invalidPoints[i]) { + continue; + } + vmath::vec3 p = _points[i + indexOffset] - offset; + float v = _velocities[i + indexOffset][diridx]; + PointData pdata(p.x, p.y, p.z, v); + AffineData adata; + + if (dir == Direction::U) { + adata = AffineData(_affineX[i + indexOffset]); + } else if (dir == Direction::V) { + adata = AffineData(_affineY[i + indexOffset]); + } else if (dir == Direction::W) { + adata = AffineData(_affineZ[i + indexOffset]); + } + + if (countData->simpleGridIndices[i] >= 0) { + int blockid = countData->simpleGridIndices[i]; int sortedIndex = blockToParticleIndexCurrent[blockid]; sortedParticleData[sortedIndex] = pdata; + sortedAffineData[sortedIndex] = adata; blockToParticleIndexCurrent[blockid]++; + } else { + int numblocks = -(countData->simpleGridIndices[i]); + for (int blockidx = 0; blockidx < numblocks; blockidx++) { + int blockid = countData->overlappingGridIndices[currentOverlappingIndex]; + currentOverlappingIndex++; + + int sortedIndex = blockToParticleIndexCurrent[blockid]; + sortedParticleData[sortedIndex] = pdata; + sortedAffineData[sortedIndex] = adata; + blockToParticleIndexCurrent[blockid]++; + } } } } + } } -void VelocityAdvector::_advectionProducerThread(BoundedBuffer *blockQueue, - BoundedBuffer *finishedBlockQueue) { +void VelocityAdvector::_advectionFLIPProducerThread(BoundedBuffer *blockQueue, + BoundedBuffer *finishedBlockQueue) { float eps = 1e-6; float r = _particleRadius; @@ -457,3 +534,90 @@ void VelocityAdvector::_advectionProducerThread(BoundedBuffer *blo } } + +/* + The APIC (Affine Particle-In-Cell) velocity transfer method was adapted from + Doyub Kim's 'Fluid Engine Dev' repository: + https://github.com/doyubkim/fluid-engine-dev +*/ +void VelocityAdvector::_advectionAPICProducerThread(BoundedBuffer *blockQueue, + BoundedBuffer *finishedBlockQueue) { + + float eps = 1e-6; + GridIndex indices[8]; + float weights[8]; + + while (blockQueue->size() > 0) { + std::vector computeBlocks; + int numBlocks = blockQueue->pop(_numBlocksPerJob, computeBlocks); + if (numBlocks == 0) { + continue; + } + + for (size_t bidx = 0; bidx < computeBlocks.size(); bidx++) { + ComputeBlock block = computeBlocks[bidx]; + GridIndex blockIndex = block.gridBlock.index; + vmath::vec3 blockPositionOffset = Grid3d::GridIndexToPosition(blockIndex, _chunkWidth * _dx); + + for (int pidx = 0; pidx < block.numParticles; pidx++) { + + PointData pdata = block.particleData[pidx]; + AffineData adata = block.affineData[pidx]; + + vmath::vec3 p(pdata.x, pdata.y, pdata.z); + p -= blockPositionOffset; + float velocity = pdata.v; + vmath::vec3 affine = vmath::vec3(adata.x, adata.y, adata.z); + + GridIndex g = Grid3d::positionToGridIndex(p, _dx); + vmath::vec3 gpos = Grid3d::GridIndexToPosition(g, _dx); + vmath::vec3 ipos = (p - gpos) / _dx; + + indices[0] = GridIndex(g.i, g.j, g.k); + indices[1] = GridIndex(g.i + 1, g.j, g.k); + indices[2] = GridIndex(g.i, g.j + 1, g.k); + indices[3] = GridIndex(g.i + 1, g.j + 1, g.k); + indices[4] = GridIndex(g.i, g.j, g.k + 1); + indices[5] = GridIndex(g.i + 1, g.j, g.k + 1); + indices[6] = GridIndex(g.i, g.j + 1, g.k + 1); + indices[7] = GridIndex(g.i + 1, g.j + 1, g.k + 1); + + weights[0] = (1.0f - ipos.x) * (1.0f - ipos.y) * (1.0f - ipos.z); + weights[1] = ipos.x * (1.0f - ipos.y) * (1.0f - ipos.z); + weights[2] = (1.0f - ipos.x) * ipos.y * (1.0f - ipos.z); + weights[3] = ipos.x * ipos.y * (1.0f - ipos.z); + weights[4] = (1.0f - ipos.x) * (1.0f - ipos.y) * ipos.z; + weights[5] = ipos.x * (1.0f - ipos.y) * ipos.z; + weights[6] = (1.0f - ipos.x) * ipos.y * ipos.z; + weights[7] = ipos.x * ipos.y * ipos.z; + + for (int gidx = 0; gidx < 8; gidx++) { + GridIndex index = indices[gidx]; + if (index.i < 0 || index.j < 0 || index.k < 0 || + index.i >= _chunkWidth || index.j >= _chunkWidth || index.k >= _chunkWidth) { + continue; + } + + vmath::vec3 nodepos = Grid3d::GridIndexToPosition(index, _dx); + float apicTerm = vmath::dot(affine, nodepos - p); + float weight = weights[gidx]; + + int flatidx = Grid3d::getFlatIndex(index, _chunkWidth, _chunkWidth); + block.gridBlock.data[flatidx].scalar += weight * (velocity + apicTerm); + block.gridBlock.data[flatidx].weight += weight; + } + + } + + int numVals = _chunkWidth * _chunkWidth * _chunkWidth; + for (int i = 0; i < numVals; i++) { + if (block.gridBlock.data[i].weight > eps) { + block.gridBlock.data[i].scalar /= block.gridBlock.data[i].weight; + } + } + + finishedBlockQueue->push(block); + } + } + +} diff --git a/src/engine/velocityadvector.h b/src/engine/velocityadvector.h index b839fe7c..cc2e6579 100644 --- a/src/engine/velocityadvector.h +++ b/src/engine/velocityadvector.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -58,14 +58,23 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #include "blockarray3d.h" #include "boundedbuffer.h" #include "macvelocityfield.h" +#include "particlesystem.h" + + +enum class VelocityAdvectorTransferMethod : char { + FLIP = 0x00, + APIC = 0x01 +}; struct VelocityAdvectorParameters { - FragmentedVector *particles; + ParticleSystem *particles; MACVelocityField *vfield; ValidVelocityComponentGrid *validVelocities; double particleRadius = 1.0; + VelocityAdvectorTransferMethod velocityTransferMethod = VelocityAdvectorTransferMethod::FLIP; }; + class VelocityAdvector { public: @@ -109,9 +118,22 @@ class VelocityAdvector { : x(px), y(py), z(pz), v(vel) {} }; + struct AffineData { + float x = 0.0f; + float y = 0.0f; + float z = 0.0f; + + AffineData() {} + AffineData(float vx, float vy, float vz) + : x(vx), y(vy), z(vz) {} + AffineData(vmath::vec3 v) + : x(v.x), y(v.y), z(v.z) {} + }; + struct ComputeBlock { GridBlock gridBlock; - PointData *particleData; + PointData *particleData = nullptr; + AffineData *affineData = nullptr; int numParticles = 0; float radius = 0.0f; }; @@ -134,18 +156,31 @@ class VelocityAdvector { Direction dir); void _sortParticlesIntoBlocks(ParticleGridCountData &countdata, std::vector &sortedParticleData, + std::vector &sortedAffineData, std::vector &blockToParticleIndex, Direction dir); - void _advectionProducerThread(BoundedBuffer *blockQueue, + void _advectionFLIPProducerThread(BoundedBuffer *blockQueue, BoundedBuffer *finishedBlockQueue); + void _advectionAPICProducerThread(BoundedBuffer *blockQueue, + BoundedBuffer *finishedBlockQueue); + + inline bool _isFLIP() { return _velocityTransferMethod == VelocityAdvectorTransferMethod::FLIP; } + inline bool _isAPIC() { return _velocityTransferMethod == VelocityAdvectorTransferMethod::APIC; } // Parameters - FragmentedVector *_particles; + ParticleSystem *_particles; MACVelocityField *_vfield; ValidVelocityComponentGrid *_validVelocities; std::vector _points; std::vector _velocities; + VelocityAdvectorTransferMethod _velocityTransferMethod = VelocityAdvectorTransferMethod::FLIP; + + // APIC Data + std::vector _affineX; + std::vector _affineY; + std::vector _affineZ; + double _dx = 0.0; double _chunkdx = 0.0; double _particleRadius = 0.0; diff --git a/src/engine/versionutils.cpp.in b/src/engine/versionutils.cpp.in index f2fbf8cd..27402bf1 100644 --- a/src/engine/versionutils.cpp.in +++ b/src/engine/versionutils.cpp.in @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/versionutils.h b/src/engine/versionutils.h index 70f8e205..0400dcb1 100644 --- a/src/engine/versionutils.h +++ b/src/engine/versionutils.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/viscositysolver.cpp b/src/engine/viscositysolver.cpp index d201048c..403c7fe4 100644 --- a/src/engine/viscositysolver.cpp +++ b/src/engine/viscositysolver.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -39,6 +39,7 @@ SOFTWARE. #include "macvelocityfield.h" #include "particlelevelset.h" #include "meshlevelset.h" +#include "interpolation.h" ViscositySolver::ViscositySolver() { } @@ -63,7 +64,6 @@ bool ViscositySolver::applyViscosityToVelocityField(ViscositySolverParameters pa std::vector soln(matsize, 0); _initializeLinearSystem(matrix, rhs); - _destroyVolumeGrid(); bool success = _solveLinearSystem(matrix, rhs, soln); if (!success) { @@ -92,6 +92,7 @@ void ViscositySolver::_initialize(ViscositySolverParameters params) { _liquidSDF = params.liquidSDF; _solidSDF = params.solidSDF; _viscosity = params.viscosity; + _solverTolerance = params.errorTolerance; } void ViscositySolver::_computeFaceStateGrid() { @@ -202,8 +203,6 @@ void ViscositySolver::_computeSolidCenterPhiThread(int startidx, int endidx, } void ViscositySolver::_computeVolumeGrid() { - _volumes = ViscosityVolumeGrid(_isize, _jsize, _ksize); - Array3d validCells(_isize + 1, _jsize + 1, _ksize + 1, false); for (int k = 0; k < _ksize; k++) { for (int j = 0; j < _jsize; j++) { @@ -236,22 +235,32 @@ void ViscositySolver::_computeVolumeGrid() { validCells = tempValid; } + if (_volumes.isize != _isize || _volumes.jsize != _jsize || _volumes.ksize != _ksize) { + _volumes = ViscosityVolumeGrid(_isize, _jsize, _ksize); + _subcellVolumeGrid = Array3d(2 * _isize, 2 * _jsize, 2 * _ksize, 0.0f); + } else { + _volumes.clear(); + _subcellVolumeGrid.fill(0.0f); + } + + vmath::vec3 centerStart(0.25f * _dx, 0.25f * _dx, 0.25f * _dx); + _estimateVolumeFractions(&_subcellVolumeGrid, &validCells, centerStart, 0.5f * _dx); + struct WorkGroup { Array3d *grid; - vmath::vec3 offset; - WorkGroup(Array3d *gridptr, vmath::vec3 gridoffset) : - grid(gridptr), offset(gridoffset) {} + GridIndex gridOffset; + WorkGroup(Array3d *gridptr, GridIndex gridoffset) : + grid(gridptr), gridOffset(gridoffset) {} }; - float hdx = 0.5 * _dx; std::vector workqueue({ - WorkGroup(&(_volumes.center), vmath::vec3(hdx, hdx, hdx)), - WorkGroup(&(_volumes.U), vmath::vec3(0, hdx, hdx)), - WorkGroup(&(_volumes.V), vmath::vec3(hdx, 0, hdx)), - WorkGroup(&(_volumes.W), vmath::vec3(hdx, hdx, 0 )), - WorkGroup(&(_volumes.edgeU), vmath::vec3(hdx, 0, 0 )), - WorkGroup(&(_volumes.edgeV), vmath::vec3(0, hdx, 0 )), - WorkGroup(&(_volumes.edgeW), vmath::vec3(0, 0, hdx)) + WorkGroup(&(_volumes.center), GridIndex( 0, 0, 0)), + WorkGroup(&(_volumes.U), GridIndex(-1, 0, 0)), + WorkGroup(&(_volumes.V), GridIndex( 0, -1, 0)), + WorkGroup(&(_volumes.W), GridIndex( 0, 0, -1)), + WorkGroup(&(_volumes.edgeU), GridIndex( 0, -1, -1)), + WorkGroup(&(_volumes.edgeV), GridIndex(-1, 0, -1)), + WorkGroup(&(_volumes.edgeW), GridIndex(-1, -1, 0)) }); int numCPU = ThreadUtils::getMaxThreadCount(); @@ -265,8 +274,9 @@ void ViscositySolver::_computeVolumeGrid() { WorkGroup workgroup = workqueue.back(); workqueue.pop_back(); - threads[tidx] = std::thread(&ViscositySolver::_estimateVolumeFractions, this, - workgroup.grid, workgroup.offset, &validCells); + threads[tidx] = std::thread(&ViscositySolver::_computeVolumeGridThread, this, + workgroup.grid, &validCells, &_subcellVolumeGrid, + workgroup.gridOffset); } for (int tidx = 0; tidx < numthreads; tidx++) { @@ -276,95 +286,90 @@ void ViscositySolver::_computeVolumeGrid() { } void ViscositySolver::_estimateVolumeFractions(Array3d *volumes, + Array3d *validCells, vmath::vec3 centerStart, - Array3d *validCells) { + float dx) { - Array3d nodalPhi(volumes->width + 1, volumes->height + 1, volumes->depth + 1); - Array3d isNodalSet(volumes->width + 1, volumes->height + 1, volumes->depth + 1, false); + int gridsize = volumes->width * volumes->height * volumes->depth; + int numCPU = ThreadUtils::getMaxThreadCount(); + int numthreads = (int)fmin(numCPU, gridsize); + std::vector threads(numthreads); + std::vector intervals = ThreadUtils::splitRangeIntoIntervals(0, gridsize, numthreads); + for (int i = 0; i < numthreads; i++) { + threads[i] = std::thread(&ViscositySolver::_estimateVolumeFractionsThread, this, + intervals[i], intervals[i + 1], + volumes, validCells, centerStart, dx); + } - volumes->fill(0); - float hdx = 0.5f * _dx; - for(int k = 0; k < volumes->depth; k++) { - for(int j = 0; j < volumes->height; j++) { - for(int i = 0; i < volumes->width; i++) { - if (!validCells->get(i, j, k)) { - continue; - } + for (int i = 0; i < numthreads; i++) { + threads[i].join(); + } - vmath::vec3 centre = centerStart + Grid3d::GridIndexToCellCenter(i, j, k, _dx); +} - if (!isNodalSet(i, j, k)) { - float n = _liquidSDF->trilinearInterpolate(centre + vmath::vec3(-hdx, -hdx, -hdx)); - nodalPhi.set(i, j, k, n); - isNodalSet.set(i, j, k, true); - } - float phi000 = nodalPhi(i, j, k); +void ViscositySolver::_estimateVolumeFractionsThread(int startidx, int endidx, + Array3d *volumes, + Array3d *validCells, + vmath::vec3 centerStart, + float dx) { - if (!isNodalSet(i, j, k + 1)) { - float n = _liquidSDF->trilinearInterpolate(centre + vmath::vec3(-hdx, -hdx, hdx)); - nodalPhi.set(i, j, k + 1, n); - isNodalSet.set(i, j, k + 1, true); - } - float phi001 = nodalPhi(i, j, k + 1); + int isize = volumes->width; + int jsize = volumes->height; + for (int idx = startidx; idx < endidx; idx++) { + GridIndex g = Grid3d::getUnflattenedIndex(idx, isize, jsize); + int i = g.i; + int j = g.j; + int k = g.k; - if (!isNodalSet(i, j + 1, k)) { - float n = _liquidSDF->trilinearInterpolate(centre + vmath::vec3(-hdx, hdx, -hdx)); - nodalPhi.set(i, j + 1, k, n); - isNodalSet.set(i, j + 1, k, true); - } - float phi010 = nodalPhi(i, j + 1, k); + if (!validCells->get(i / 2, j / 2, k / 2)) { + continue; + } - if (!isNodalSet(i, j + 1, k + 1)) { - float n = _liquidSDF->trilinearInterpolate(centre + vmath::vec3(-hdx, hdx, hdx)); - nodalPhi.set(i, j + 1, k + 1, n); - isNodalSet.set(i, j + 1, k + 1, true); - } - float phi011 = nodalPhi(i, j + 1, k + 1); + vmath::vec3 center = centerStart + vmath::vec3(i * dx, j * dx, k * dx); + float hdx = 0.5f * dx; - if (!isNodalSet(i + 1, j, k)) { - float n = _liquidSDF->trilinearInterpolate(centre + vmath::vec3(hdx, -hdx, -hdx)); - nodalPhi.set(i + 1, j, k, n); - isNodalSet.set(i + 1, j, k, true); - } - float phi100 = nodalPhi(i + 1, j, k); + float phi000 = _liquidSDF->trilinearInterpolate(center + vmath::vec3(-hdx, -hdx, -hdx)); + float phi001 = _liquidSDF->trilinearInterpolate(center + vmath::vec3(-hdx, -hdx, +hdx)); + float phi010 = _liquidSDF->trilinearInterpolate(center + vmath::vec3(-hdx, +hdx, -hdx)); + float phi011 = _liquidSDF->trilinearInterpolate(center + vmath::vec3(-hdx, +hdx, +hdx)); + float phi100 = _liquidSDF->trilinearInterpolate(center + vmath::vec3(+hdx, -hdx, -hdx)); + float phi101 = _liquidSDF->trilinearInterpolate(center + vmath::vec3(+hdx, -hdx, +hdx)); + float phi110 = _liquidSDF->trilinearInterpolate(center + vmath::vec3(+hdx, +hdx, -hdx)); + float phi111 = _liquidSDF->trilinearInterpolate(center + vmath::vec3(+hdx, +hdx, +hdx)); - if (!isNodalSet(i + 1, j, k + 1)) { - float n = _liquidSDF->trilinearInterpolate(centre + vmath::vec3(hdx, -hdx, hdx)); - nodalPhi.set(i + 1, j, k + 1, n); - isNodalSet.set(i + 1, j, k + 1, true); - } - float phi101 = nodalPhi(i + 1, j, k + 1); + volumes->set(i, j, k, LevelsetUtils::volumeFraction( + phi000, phi100, phi010, phi110, phi001, phi101, phi011, phi111 + )); + } +} - if (!isNodalSet(i + 1, j + 1, k)) { - float n = _liquidSDF->trilinearInterpolate(centre + vmath::vec3(hdx, hdx, -hdx)); - nodalPhi.set(i + 1, j + 1, k, n); - isNodalSet.set(i + 1, j + 1, k, true); - } - float phi110 = nodalPhi(i + 1, j + 1, k); +void ViscositySolver::_computeVolumeGridThread(Array3d *volumes, + Array3d *validCells, + Array3d *subcellVolumes, + GridIndex gridOffset) { - if (!isNodalSet(i + 1, j + 1, k + 1)) { - float n = _liquidSDF->trilinearInterpolate(centre + vmath::vec3(hdx, hdx, hdx)); - nodalPhi.set(i + 1, j + 1, k + 1, n); - isNodalSet.set(i + 1, j + 1, k + 1, true); + for (int k = 1; k < _ksize; k++) { + for (int j = 1; j < _jsize; j++) { + for (int i = 1; i < _isize; i++) { + if (!validCells->get(i, j, k)) { + continue; } - float phi111 = nodalPhi(i + 1, j + 1, k + 1); - - if (phi000 < 0 && phi001 < 0 && phi010 < 0 && phi011 < 0 && - phi100 < 0 && phi101 < 0 && phi110 < 0 && phi111 < 0) { - volumes->set(i, j, k, 1.0); - } else if (phi000 >= 0 && phi001 >= 0 && phi010 >= 0 && phi011 >= 0 && - phi100 >= 0 && phi101 >= 0 && phi110 >= 0 && phi111 >= 0) { - volumes->set(i, j, k, 0.0); - } else { - volumes->set(i, j, k, LevelsetUtils::volumeFraction( - phi000, phi100, phi010, phi110, phi001, phi101, phi011, phi111 - )); + + int base_i = 2 * i + gridOffset.i; + int base_j = 2 * j + gridOffset.j; + int base_k = 2 * k + gridOffset.k; + for (int k_off = 0; k_off < 2; k_off++) { + for (int j_off = 0; j_off < 2; j_off++) { + for (int i_off = 0; i_off < 2; i_off++) { + volumes->add(i, j, k, subcellVolumes->get(base_i + i_off, base_j + j_off, base_k + k_off)); + } + } } + volumes->set(i, j, k, 0.125f * volumes->get(i, j, k)); + } } - } - } void ViscositySolver::_destroyVolumeGrid() { diff --git a/src/engine/viscositysolver.h b/src/engine/viscositysolver.h index a5118d7b..fd3ee477 100644 --- a/src/engine/viscositysolver.h +++ b/src/engine/viscositysolver.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -42,6 +42,7 @@ struct ViscositySolverParameters { ParticleLevelSet *liquidSDF; MeshLevelSet *solidSDF; Array3d *viscosity; + double errorTolerance = 1e-4; }; class ViscositySolver { @@ -76,6 +77,16 @@ class ViscositySolver { edgeV(isize + 1, jsize, ksize + 1, 0.0f), edgeW(isize + 1, jsize + 1, ksize, 0.0f) {} + void clear() { + center.fill(0.0f); + U.fill(0.0f); + V.fill(0.0f); + W.fill(0.0f); + edgeU.fill(0.0f); + edgeV.fill(0.0f); + edgeW.fill(0.0f); + } + void destroy() { isize = 0; jsize = 0; @@ -179,8 +190,19 @@ class ViscositySolver { Array3d *solidCenterPhi); void _computeVolumeGrid(); void _estimateVolumeFractions(Array3d *volumes, + Array3d *validCells, vmath::vec3 centerStart, - Array3d *validCells); + float dx); + void _estimateVolumeFractionsThread(int startidx, int endidx, + Array3d *volumes, + Array3d *validCells, + vmath::vec3 centerStart, + float dx); + void _computeVolumeGridThread(Array3d *volumes, + Array3d *validCells, + Array3d *subcellVolumes, + GridIndex gridOffset); + void _destroyVolumeGrid(); void _computeMatrixIndexTable(); void _initializeLinearSystem(SparseMatrixf &matrix, std::vector &rhs); @@ -216,13 +238,13 @@ class ViscositySolver { FaceStateGrid _state; ViscosityVolumeGrid _volumes; + Array3d _subcellVolumeGrid; MatrixIndexer _matrixIndex; double _solverTolerance = 1e-4; double _acceptableTolerace = 10.0; - int _maxSolverIterations = 700; + int _maxSolverIterations = 1400; std::string _solverStatus; - }; diff --git a/src/engine/vmath.cpp b/src/engine/vmath.cpp index ed7a2295..a7186487 100644 --- a/src/engine/vmath.cpp +++ b/src/engine/vmath.cpp @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/engine/vmath.h b/src/engine/vmath.h index db4fe8a8..f3c46408 100644 --- a/src/engine/vmath.h +++ b/src/engine/vmath.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (C) 2020 Ryan L. Guy +Copyright (C) 2021 Ryan L. Guy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal