diff options
-rw-r--r-- | release/scripts/startup/bl_ui/properties_physics_fluid.py | 402 |
1 files changed, 259 insertions, 143 deletions
diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py index 94611808059..451b17b72b7 100644 --- a/release/scripts/startup/bl_ui/properties_physics_fluid.py +++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py @@ -17,8 +17,11 @@ # ##### END GPL LICENSE BLOCK ##### # <pep8 compliant> + import bpy -from bpy.types import Panel, Menu +from bpy.types import ( + Panel, +) from bpy.app.translations import pgettext_iface as iface_ from bl_operators.presets import PresetMenu @@ -35,172 +38,239 @@ class PhysicButtonsPanel: bl_region_type = 'WINDOW' bl_context = "physics" - @classmethod - def poll(cls, context): + def poll_fluid(context): ob = context.object - return (ob and ob.type == 'MESH') and context.engine in cls.COMPAT_ENGINES and (context.fluid) + if not ((ob and ob.type == 'MESH') and (context.fluid)): + return False + + return (bpy.app.build_options.mod_fluid) + + def poll_fluid_settings(context): + if not (PhysicButtonsPanel.poll_fluid(context)): + return False + + md = context.fluid + return md and md.settings and (md.settings.type != 'NONE') + + def poll_fluid_domain(context): + if not PhysicButtonsPanel.poll_fluid(context): + return False + + md = context.fluid + return md and md.settings and (md.settings.type == 'DOMAIN') class PHYSICS_PT_fluid(PhysicButtonsPanel, Panel): bl_label = "Fluid" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} + @classmethod + def poll(cls, context): + ob = context.object + return (ob and ob.type == 'MESH') and context.engine in cls.COMPAT_ENGINES and (context.fluid) + def draw(self, context): layout = self.layout + layout.use_property_split = True - md = context.fluid - fluid = md.settings - - col = layout.column() if not bpy.app.build_options.mod_fluid: + col = layout.column() + col.alignment = 'RIGHT' col.label("Built without fluids") return + md = context.fluid + fluid = md.settings + + col = layout.column() col.prop(fluid, "type") + + +class PHYSICS_PT_fluid_settings(PhysicButtonsPanel, Panel): + bl_label = "Settings" + bl_parent_id = "PHYSICS_PT_fluid" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + if not PhysicButtonsPanel.poll_fluid_settings(context): + return False + + return (context.engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + md = context.fluid + fluid = md.settings if fluid.type not in {'NONE', 'DOMAIN', 'PARTICLE', 'FLUID', 'OBSTACLE'}: - col.prop(fluid, "use") + self.layout.prop(fluid, "use", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + md = context.fluid + fluid = md.settings + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) - layout = layout.column() if fluid.type not in {'NONE', 'DOMAIN', 'PARTICLE', 'FLUID', 'OBSTACLE'}: - layout.active = fluid.use + flow.active = fluid.use if fluid.type == 'DOMAIN': - # odd formatting here so translation script can extract string - layout.operator("fluid.bake", text=iface_("Bake (Req. Memory: %s)") % fluid.memory_estimate, - translate=False, icon='MOD_FLUIDSIM') + col = flow.column() if bpy.app.build_options.openmp: - layout.prop(fluid, "threads", text="Simulation Threads") + col.prop(fluid, "threads", text="Simulation Threads") + col.separator() - split = layout.split() + col.prop(fluid, "resolution", text="Final Resolution") + col.prop(fluid, "preview_resolution", text="Preview") - col = split.column() - col.label(text="Resolution:") - col.prop(fluid, "resolution", text="Final") - col.label(text="Render Display:") - col.prop(fluid, "render_display_mode", text="") + col.separator() - col = split.column() - col.label() - col.prop(fluid, "preview_resolution", text="Preview") - col.label(text="Viewport Display:") - col.prop(fluid, "viewport_display_mode", text="") + col = flow.column() + col.prop(fluid, "render_display_mode", text="Render Display") + col.prop(fluid, "viewport_display_mode", text="Viewport") - split = layout.split() + col.separator() - col = split.column() - col.label(text="Time:") + col = flow.column() sub = col.column(align=True) - sub.prop(fluid, "start_time", text="Start") + sub.prop(fluid, "start_time", text="Time Start") sub.prop(fluid, "end_time", text="End") col.prop(fluid, "simulation_rate", text="Speed") - col = split.column() - col.label() - sub = col.column(align=True) - sub.prop(fluid, "use_speed_vectors") - sub.prop(fluid, "use_reverse_frames") + col = flow.column() + col.prop(fluid, "use_speed_vectors") + col.prop(fluid, "use_reverse_frames") col.prop(fluid, "frame_offset", text="Offset") - layout.prop(fluid, "filepath", text="") - elif fluid.type == 'FLUID': - split = layout.split() - - col = split.column() - col.label(text="Volume Initialization:") - col.prop(fluid, "volume_initialization", text="") + col = flow.column() + col.prop(fluid, "volume_initialization", text="Volume Initialization") col.prop(fluid, "use_animated_mesh") - col = split.column() - col.label(text="Initial Velocity:") - col.prop(fluid, "initial_velocity", text="") + col = flow.column() + col.prop(fluid, "initial_velocity", text="Initial Velocity") elif fluid.type == 'OBSTACLE': - split = layout.split() - - col = split.column() - col.label(text="Volume Initialization:") - col.prop(fluid, "volume_initialization", text="") + col = flow.column() + col.prop(fluid, "volume_initialization", text="Volume Initialization") col.prop(fluid, "use_animated_mesh") - col = split.column() - subsplit = col.split() - subcol = subsplit.column() - if fluid.use_animated_mesh: - subcol.enabled = False - subcol.label(text="Slip Type:") - subcol.prop(fluid, "slip_type", text="") + col = flow.column() + subcol = col.column() + subcol.enabled = not fluid.use_animated_mesh + subcol.prop(fluid, "slip_type", text="Slip Type") + if fluid.slip_type == 'PARTIALSLIP': - subcol.prop(fluid, "partial_slip_factor", slider=True, text="Amount") + subcol.prop(fluid, "partial_slip_factor", text="Amount", slider=True) - col.label(text="Impact:") - col.prop(fluid, "impact_factor", text="Factor") + col.prop(fluid, "impact_factor", text="Impact Factor") elif fluid.type == 'INFLOW': - split = layout.split() - - col = split.column() - col.label(text="Volume Initialization:") - col.prop(fluid, "volume_initialization", text="") + col = flow.column() + col.prop(fluid, "volume_initialization", text="Volume Initialization") col.prop(fluid, "use_animated_mesh") + row = col.row() row.active = not fluid.use_animated_mesh row.prop(fluid, "use_local_coords") - col = split.column() - col.label(text="Inflow Velocity:") - col.prop(fluid, "inflow_velocity", text="") + col = flow.column() + col.prop(fluid, "inflow_velocity", text="Inflow Velocity") elif fluid.type == 'OUTFLOW': - col = layout.column() - col.label(text="Volume Initialization:") - col.prop(fluid, "volume_initialization", text="") + col = flow.column() + col.prop(fluid, "volume_initialization", text="Volume Initialization") + + col = flow.column() col.prop(fluid, "use_animated_mesh") elif fluid.type == 'PARTICLE': - split = layout.split() - - col = split.column() - col.label(text="Influence:") - col.prop(fluid, "particle_influence", text="Size") + col = flow.column() + col.prop(fluid, "particle_influence", text="Influence Size") col.prop(fluid, "alpha_influence", text="Alpha") - col = split.column() - col.label(text="Type:") + col = flow.column() col.prop(fluid, "use_drops") col.prop(fluid, "use_floats") col.prop(fluid, "show_tracer") - layout.prop(fluid, "filepath", text="") - elif fluid.type == 'CONTROL': - split = layout.split() - - col = split.column() - col.label(text="") + col = flow.column() col.prop(fluid, "quality", slider=True) col.prop(fluid, "use_reverse_frames") - col = split.column() - col.label(text="Time:") - sub = col.column(align=True) - sub.prop(fluid, "start_time", text="Start") - sub.prop(fluid, "end_time", text="End") + col = flow.column() + col.prop(fluid, "start_time", text="Time Start") + col.prop(fluid, "end_time", text="End") - split = layout.split() + col.separator() - col = split.column() - col.label(text="Attraction Force:") - sub = col.column(align=True) - sub.prop(fluid, "attraction_strength", text="Strength") - sub.prop(fluid, "attraction_radius", text="Radius") + col = flow.column() + col.prop(fluid, "attraction_strength", text="Attraction Strength") + col.prop(fluid, "attraction_radius", text="Radius") - col = split.column() - col.label(text="Velocity Force:") - sub = col.column(align=True) - sub.prop(fluid, "velocity_strength", text="Strength") - sub.prop(fluid, "velocity_radius", text="Radius") + col.separator() + + col = flow.column(align=True) + col.prop(fluid, "velocity_strength", text="Velocity Strength") + col.prop(fluid, "velocity_radius", text="Radius") + + +class PHYSICS_PT_fluid_particle_cache(PhysicButtonsPanel, Panel): + bl_label = "Cache" + bl_parent_id = "PHYSICS_PT_fluid" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + if not PhysicButtonsPanel.poll_fluid_settings(context): + return False + + md = context.fluid + return md and md.settings and (md.settings.type == 'PARTICLE') and (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + + md = context.fluid + fluid = md.settings + + layout.prop(fluid, "filepath", text="") + + +class PHYSICS_PT_domain_bake(PhysicButtonsPanel, Panel): + bl_label = "Bake" + bl_parent_id = 'PHYSICS_PT_fluid' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + if not PhysicButtonsPanel.poll_fluid_domain(context): + return False + + return (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + + md = context.fluid + fluid = md.settings + + row = layout.row(align=True) + row.alignment = 'RIGHT' + row.label("Cache Path") + + layout.prop(fluid, "filepath", text="") + + # odd formatting here so translation script can extract string + layout.operator( + "fluid.bake", text=iface_("Bake (Req. Memory: %s)") % fluid.memory_estimate, + translate=False, icon='MOD_FLUIDSIM' + ) class PHYSICS_PT_domain_gravity(PhysicButtonsPanel, Panel): @@ -211,48 +281,81 @@ class PHYSICS_PT_domain_gravity(PhysicButtonsPanel, Panel): @classmethod def poll(cls, context): - md = context.fluid - return md and md.settings and (md.settings.type == 'DOMAIN') and context.engine in cls.COMPAT_ENGINES + if not PhysicButtonsPanel.poll_fluid_domain(context): + return False + + return (context.engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout + layout.use_property_split = True fluid = context.fluid.settings scene = context.scene - split = layout.split() + col = layout.column() + + use_gravity = scene.use_gravity + use_units = scene.unit_settings.system != 'NONE' + + if use_gravity or use_units: + s_gravity = " Gravity" if use_gravity else "" + s_units = " Units" if use_units else "" + s_and = " and " if use_gravity and use_units else "" + warn = f"Using {s_gravity}{s_and}{s_units} from Scene" - col = split.column() - if scene.use_gravity: - col.label(text="Use Scene Gravity", icon='SCENE_DATA') - sub = col.column() - sub.enabled = False - sub.prop(fluid, "gravity", text="") - else: - col.label(text="Gravity:") - col.prop(fluid, "gravity", text="") - - if scene.unit_settings.system != 'NONE': - col.label(text="Use Scene Size Units", icon='SCENE_DATA') sub = col.column() - sub.enabled = False - sub.prop(fluid, "simulation_scale", text="Meters") - else: - col.label(text="Real World Size:") - col.prop(fluid, "simulation_scale", text="Meters") + sub.alignment = 'RIGHT' + sub.label(text=warn) + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) - col = split.column() - FLUID_PT_presets.draw_menu(col, text="Viscosity Presets") + col = flow.column() + sub = col.column() + sub.enabled = not use_gravity + sub.prop(fluid, "gravity", text="Gravity") - sub = col.column(align=True) - sub.prop(fluid, "viscosity_base", text="Base") - sub.prop(fluid, "viscosity_exponent", text="Exponent", slider=True) + sub = col.column() + sub.enabled = not use_units + sub.prop(fluid, "simulation_scale", text="Scene Size Meters" if use_units else "World Size Meters") - col.label(text="Optimization:") - col.prop(fluid, "grid_levels", slider=True) + col.separator() + + col = flow.column() + col.prop(fluid, "grid_levels", text="Optimization", slider=True) col.prop(fluid, "compressibility", slider=True) +class PHYSICS_PT_domain_viscosity(PhysicButtonsPanel, Panel): + bl_label = "Viscosity" + bl_parent_id = 'PHYSICS_PT_fluid' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + if not PhysicButtonsPanel.poll_fluid_domain(context): + return False + + return (context.engine in cls.COMPAT_ENGINES) + + def draw_header_preset(self, context): + FLUID_PT_presets.draw_panel_header(self.layout) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) + + fluid = context.fluid.settings + + col = flow.column() + col.prop(fluid, "viscosity_base", text="Base") + + col = flow.column() + col.prop(fluid, "viscosity_exponent", text="Exponent", slider=True) + + class PHYSICS_PT_domain_boundary(PhysicButtonsPanel, Panel): bl_label = "Boundary" bl_parent_id = 'PHYSICS_PT_fluid' @@ -261,27 +364,30 @@ class PHYSICS_PT_domain_boundary(PhysicButtonsPanel, Panel): @classmethod def poll(cls, context): - md = context.fluid - return md and md.settings and (md.settings.type == 'DOMAIN') and context.engine in cls.COMPAT_ENGINES + if not PhysicButtonsPanel.poll_fluid_domain(context): + return False + + return (context.engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) fluid = context.fluid.settings - split = layout.split() + col = flow.column() + col.prop(fluid, "slip_type", text="Type") + + col.separator() - col = split.column() - col.label(text="Slip Type:") - col.prop(fluid, "slip_type", text="") if fluid.slip_type == 'PARTIALSLIP': col.prop(fluid, "partial_slip_factor", slider=True, text="Amount") - col.prop(fluid, "use_surface_noobs") - col = split.column() - col.label(text="Surface:") - col.prop(fluid, "surface_smooth", text="Smoothing") + col = flow.column() + col.prop(fluid, "surface_smooth", text="Surface Smoothing") col.prop(fluid, "surface_subdivisions", text="Subdivisions") + col.prop(fluid, "use_surface_noobs") class PHYSICS_PT_domain_particles(PhysicButtonsPanel, Panel): @@ -292,25 +398,35 @@ class PHYSICS_PT_domain_particles(PhysicButtonsPanel, Panel): @classmethod def poll(cls, context): - md = context.fluid - return md and md.settings and (md.settings.type == 'DOMAIN') and context.engine in cls.COMPAT_ENGINES + if not PhysicButtonsPanel.poll_fluid_domain(context): + return False + + return (context.engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) fluid = context.fluid.settings - row = layout.row() - row.prop(fluid, "tracer_particles", text="Tracer") - row.prop(fluid, "generate_particles", text="Generate") + col = flow.column() + col.prop(fluid, "tracer_particles", text="Tracer") + + col = flow.column() + col.prop(fluid, "generate_particles", text="Generate") classes = ( FLUID_PT_presets, PHYSICS_PT_fluid, - PHYSICS_PT_domain_gravity, + PHYSICS_PT_fluid_settings, + PHYSICS_PT_fluid_particle_cache, + PHYSICS_PT_domain_bake, PHYSICS_PT_domain_boundary, PHYSICS_PT_domain_particles, + PHYSICS_PT_domain_gravity, + PHYSICS_PT_domain_viscosity, ) if __name__ == "__main__": # only for live edit. |