diff options
Diffstat (limited to 'release/scripts/startup/bl_ui')
8 files changed, 1017 insertions, 904 deletions
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py index 5daacbb2e44..c2bcb7d5ea5 100644 --- a/release/scripts/startup/bl_ui/__init__.py +++ b/release/scripts/startup/bl_ui/__init__.py @@ -54,10 +54,9 @@ _modules = [ "properties_physics_common", "properties_physics_dynamicpaint", "properties_physics_field", - "properties_physics_fluid", "properties_physics_rigidbody", "properties_physics_rigidbody_constraint", - "properties_physics_smoke", + "properties_physics_fluid", "properties_physics_softbody", "properties_render", "properties_output", diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 4fe6a5ac19b..d4b2c39bd5e 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -945,7 +945,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "angle") col.prop(md, "limits", slider=True) - def SMOKE(self, layout, _ob, _md): + def FLUID(self, layout, _ob, _md): layout.label(text="Settings are inside the Physics tab") def SMOOTH(self, layout, ob, md): diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py index fa4ec391405..21abf8bb34c 100644 --- a/release/scripts/startup/bl_ui/properties_particle.py +++ b/release/scripts/startup/bl_ui/properties_particle.py @@ -55,7 +55,7 @@ def particle_panel_poll(cls, context): if not settings: return False - return settings.is_fluid is False and (engine in cls.COMPAT_ENGINES) + return (settings.is_fluid is False) and (engine in cls.COMPAT_ENGINES) def particle_get_settings(context): @@ -207,7 +207,7 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel): col = layout.column() - if part.is_fluid is False: + if (part.is_fluid is False): row = col.row() row.enabled = particle_panel_enabled(context, psys) row.template_ID(psys, "settings", new="particle.new") diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py index b69f2233035..5397020a521 100644 --- a/release/scripts/startup/bl_ui/properties_physics_common.py +++ b/release/scripts/startup/bl_ui/properties_physics_common.py @@ -99,8 +99,7 @@ class PHYSICS_PT_add(PhysicButtonsPanel, Panel): physics_add(col, context.soft_body, "Soft Body", 'SOFT_BODY', 'MOD_SOFT', True) if obj.type == 'MESH': - physics_add(col, context.fluid, "Fluid", 'FLUID_SIMULATION', 'MOD_FLUIDSIM', True) - physics_add(col, context.smoke, "Smoke", 'SMOKE', 'MOD_SMOKE', True) + physics_add(col, context.fluid, "Fluid", 'FLUID', 'MOD_FLUIDSIM', True) physics_add_special( col, obj.rigid_body, "Rigid Body", @@ -118,7 +117,7 @@ class PHYSICS_PT_add(PhysicButtonsPanel, Panel): ) -# cache-type can be 'PSYS' 'HAIR' 'SMOKE' etc. +# cache-type can be 'PSYS' 'HAIR' 'FLUID' etc. def point_cache_ui(self, cache, enabled, cachetype): layout = self.layout @@ -141,10 +140,10 @@ def point_cache_ui(self, cache, enabled, cachetype): col.operator("ptcache.add", icon='ADD', text="") col.operator("ptcache.remove", icon='REMOVE', text="") - if cachetype in {'PSYS', 'HAIR', 'SMOKE'}: + if cachetype in {'PSYS', 'HAIR', 'FLUID'}: col = layout.column() - if cachetype == 'SMOKE': + if cachetype == 'FLUID': col.prop(cache, "use_library_path", text="Use Library Path") col.prop(cache, "use_external") @@ -160,14 +159,14 @@ def point_cache_ui(self, cache, enabled, cachetype): col.alignment = 'RIGHT' col.label(text=cache_info) else: - if cachetype in {'SMOKE', 'DYNAMIC_PAINT'}: + if cachetype in {'FLUID', 'DYNAMIC_PAINT'}: if not is_saved: col = layout.column(align=True) col.alignment = 'RIGHT' col.label(text="Cache is disabled until the file is saved") layout.enabled = False - if not cache.use_external or cachetype == 'SMOKE': + if not cache.use_external or cachetype == 'FLUID': col = layout.column(align=True) if cachetype not in {'PSYS', 'DYNAMIC_PAINT'}: @@ -175,18 +174,18 @@ def point_cache_ui(self, cache, enabled, cachetype): col.prop(cache, "frame_start", text="Simulation Start") col.prop(cache, "frame_end") - if cachetype not in {'SMOKE', 'CLOTH', 'DYNAMIC_PAINT', 'RIGID_BODY'}: + if cachetype not in {'FLUID', 'CLOTH', 'DYNAMIC_PAINT', 'RIGID_BODY'}: col.prop(cache, "frame_step") cache_info = cache.info - if cachetype != 'SMOKE' and cache_info: # avoid empty space. + if cachetype != 'FLUID' and cache_info: # avoid empty space. col = layout.column(align=True) col.alignment = 'RIGHT' col.label(text=cache_info) can_bake = True - if cachetype not in {'SMOKE', 'DYNAMIC_PAINT', 'RIGID_BODY'}: + if cachetype not in {'FLUID', 'DYNAMIC_PAINT', 'RIGID_BODY'}: if not is_saved: col = layout.column(align=True) col.alignment = 'RIGHT' @@ -269,7 +268,7 @@ def effector_weights_ui(self, weights, weight_type): col.prop(weights, "curve_guide", slider=True) col.prop(weights, "texture", slider=True) - if weight_type != 'SMOKE': + if weight_type != 'FLUID': col.prop(weights, "smokeflow", slider=True) col = flow.column() diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py index b9e690629d1..f182a025f61 100644 --- a/release/scripts/startup/bl_ui/properties_physics_fluid.py +++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py @@ -21,16 +21,17 @@ import bpy from bpy.types import ( Panel, + Menu, +) +from .properties_physics_common import ( + effector_weights_ui, ) -from bpy.app.translations import pgettext_iface as iface_ -from bl_ui.utils import PresetPanel - -class FLUID_PT_presets(PresetPanel, Panel): +class FLUID_MT_presets(Menu): bl_label = "Fluid Presets" preset_subdir = "fluid" preset_operator = "script.execute_preset" - preset_add_operator = "fluid.preset_add" + draw = Menu.draw_preset class PhysicButtonsPanel: @@ -44,23 +45,46 @@ class PhysicButtonsPanel: if not ((ob and ob.type == 'MESH') and (context.fluid)): return False - return (bpy.app.build_options.mod_fluid) + md = context.fluid + return md and (context.fluid.fluid_type != 'NONE') @staticmethod - def poll_fluid_settings(context): - if not (PhysicButtonsPanel.poll_fluid(context)): + 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 != 'NONE') + return md and (md.fluid_type == 'DOMAIN') @staticmethod - def poll_fluid_domain(context): + def poll_gas_domain(context): + if not PhysicButtonsPanel.poll_fluid(context): + return False + + md = context.fluid + if md and (md.fluid_type == 'DOMAIN'): + domain = md.domain_settings + return domain.domain_type in {'GAS'} + return False + + @staticmethod + def poll_liquid_domain(context): + if not PhysicButtonsPanel.poll_fluid(context): + return False + + md = context.fluid + if md and (md.fluid_type == 'DOMAIN'): + domain = md.domain_settings + return domain.domain_type in {'LIQUID'} + return False + + @staticmethod + def poll_fluid_flow(context): if not PhysicButtonsPanel.poll_fluid(context): return False md = context.fluid - return md and md.settings and (md.settings.type == 'DOMAIN') + return md and (md.fluid_type == 'FLOW') class PHYSICS_PT_fluid(PhysicButtonsPanel, Panel): @@ -70,325 +94,899 @@ class PHYSICS_PT_fluid(PhysicButtonsPanel, Panel): @classmethod def poll(cls, context): ob = context.object - return (ob and ob.type == 'MESH') and context.engine in cls.COMPAT_ENGINES and (context.fluid) + 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 - if not bpy.app.build_options.mod_fluid: - col = layout.column() + if not bpy.app.build_options.fluid: + col = layout.column(align=True) col.alignment = 'RIGHT' - col.label(text="Built without fluids") + col.label(text="Built without Fluid modifier") return - md = context.fluid - fluid = md.settings - col = layout.column() - col.prop(fluid, "type") + layout.prop(md, "fluid_type") -class PHYSICS_PT_fluid_flow(PhysicButtonsPanel, Panel): - bl_label = "Flow" - bl_parent_id = "PHYSICS_PT_fluid" +class PHYSICS_PT_settings(PhysicButtonsPanel, Panel): + bl_label = "Settings" + bl_parent_id = 'PHYSICS_PT_fluid' COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} @classmethod def poll(cls, context): - md = context.fluid - fluid = md.settings - - if not PhysicButtonsPanel.poll_fluid_settings(context): + if not PhysicButtonsPanel.poll_fluid(context): return False - return fluid.type in {'INFLOW', 'OUTFLOW', 'CONTROL'} and (context.engine in cls.COMPAT_ENGINES) - - def draw_header(self, context): - md = context.fluid - fluid = md.settings - self.layout.prop(fluid, "use", text="") + return (context.engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout layout.use_property_split = True md = context.fluid - fluid = md.settings + ob = context.object + scene = context.scene - flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) + if md.fluid_type == 'DOMAIN': + domain = md.domain_settings - flow.active = fluid.use + # Deactivate UI if guiding is enabled but not baked yet + layout.active = not (domain.use_guiding and not domain.cache_baked_guiding and (domain.guiding_source == "EFFECTOR" or (domain.guiding_source == "DOMAIN" and not domain.guiding_parent))) - if fluid.type == 'INFLOW': - col = flow.column() - col.prop(fluid, "volume_initialization", text="Volume Initialization") - col.prop(fluid, "use_animated_mesh") + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding + baked_data = domain.cache_baked_data - row = col.row() - row.active = not fluid.use_animated_mesh - row.prop(fluid, "use_local_coords") + row = layout.row() + row.enabled = not baking_any and not baked_data + row.prop(domain, "domain_type", expand=False) - col = flow.column() - col.prop(fluid, "inflow_velocity", text="Inflow Velocity") + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + flow.enabled = not baking_any and not baked_data - elif fluid.type == 'OUTFLOW': col = flow.column() - col.prop(fluid, "volume_initialization", text="Volume Initialization") + col.prop(domain, "resolution_max", text="Resolution Divisions") + col.prop(domain, "time_scale", text="Time Scale") + col.prop(domain, "cfl_condition", text="CFL Number") col = flow.column() - col.prop(fluid, "use_animated_mesh") + col.prop(domain, "use_adaptive_stepping", text="Use Adaptive Stepping") + col1 = col.column(align=True) + col1.enabled = domain.use_adaptive_stepping + col1.prop(domain, "timesteps_maximum", text="Timesteps Maximum") + col1.prop(domain, "timesteps_minimum", text="Minimum") - elif fluid.type == 'CONTROL': - col = flow.column() - col.prop(fluid, "quality", slider=True) - col.prop(fluid, "use_reverse_frames") + col.separator() col = flow.column() - col.prop(fluid, "start_time", text="Time Start") - col.prop(fluid, "end_time", text="End") + if scene.use_gravity: + sub = col.column() + sub.enabled = False + sub.prop(domain, "gravity", text="Using Scene Gravity", icon='SCENE_DATA') + else: + col.prop(domain, "gravity", text="Gravity") + # TODO (sebbas): Clipping var useful for manta openvdb caching? + # col.prop(domain, "clipping", text="Empty Space") + + if domain.cache_type == "MODULAR": + col.separator() + split = layout.split() - col.separator() + bake_incomplete = (domain.cache_frame_pause_data < domain.cache_frame_end) + if domain.cache_baked_data and not domain.cache_baking_data and bake_incomplete: + col = split.column() + col.operator("fluid.bake_data", text="Resume") + col = split.column() + col.operator("fluid.free_data", text="Free") + elif domain.cache_baking_data and not domain.cache_baked_data: + split.enabled = False + split.operator("fluid.pause_bake", text="Baking Data - ESC to pause") + elif not domain.cache_baked_data and not domain.cache_baking_data: + split.operator("fluid.bake_data", text="Bake Data") + else: + split.operator("fluid.free_data", text="Free Data") + + elif md.fluid_type == 'FLOW': + flow = md.flow_settings + + row = layout.row() + row.prop(flow, "flow_type", expand=False) + + grid = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + + col = grid.column() + col.prop(flow, "flow_behavior", expand=False) + if flow.flow_behavior in {'INFLOW'}: + col.prop(flow, "use_inflow", text="Use Inflow") + + col.prop(flow, "subframes", text="Sampling Substeps") + + if not flow.flow_behavior == 'OUTFLOW' and flow.flow_type in {'SMOKE', 'BOTH', 'FIRE'}: + + if flow.flow_type in {'SMOKE', 'BOTH'}: + col.prop(flow, "smoke_color", text="Smoke Color") + + col = grid.column(align=True) + col.prop(flow, "use_absolute", text="Absolute Density") + + if flow.flow_type in {'SMOKE', 'BOTH'}: + col.prop(flow, "temperature", text="Initial Temperature") + col.prop(flow, "density", text="Density") + + if flow.flow_type in {'FIRE', 'BOTH'}: + col.prop(flow, "fuel_amount", text="Fuel") + + col.separator() + col.prop_search(flow, "density_vertex_group", ob, "vertex_groups", text="Vertex Group") + + elif md.fluid_type == 'EFFECTOR': + effec = md.effec_settings + + row = layout.row() + row.prop(effec, "effec_type") + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) col = flow.column() - col.prop(fluid, "attraction_strength", text="Attraction Strength") - col.prop(fluid, "attraction_radius", text="Radius") - col.separator() + col.prop(effec, "use_plane_init", text="Is Planar") + col.prop(effec, "surface_distance", text="Surface Thickness") - col = flow.column(align=True) - col.prop(fluid, "velocity_strength", text="Velocity Strength") - col.prop(fluid, "velocity_radius", text="Radius") + if effec.effec_type == "GUIDE": + col.prop(effec, "velocity_factor", text="Velocity Factor") + col = flow.column() + col.prop(effec, "guiding_mode", text="Guiding Mode") -class PHYSICS_PT_fluid_settings(PhysicButtonsPanel, Panel): - bl_label = "Settings" - bl_parent_id = "PHYSICS_PT_fluid" +class PHYSICS_PT_borders(PhysicButtonsPanel, Panel): + bl_label = "Border Collisions" + bl_parent_id = 'PHYSICS_PT_settings' COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} @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 + layout.use_property_split = True + md = context.fluid - fluid = md.settings + domain = md.domain_settings + + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding + baked_data = domain.cache_baked_data + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + flow.enabled = not baking_any and not baked_data + + col = flow.column() + col.prop(domain, "use_collision_border_front", text="Front") + col = flow.column() + col.prop(domain, "use_collision_border_back", text="Back") + col = flow.column() + col.prop(domain, "use_collision_border_right", text="Right") + col = flow.column() + col.prop(domain, "use_collision_border_left", text="Left") + col = flow.column() + col.prop(domain, "use_collision_border_top", text="Top") + col = flow.column() + col.prop(domain, "use_collision_border_bottom", text="Bottom") + + +class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel): + bl_label = "Smoke" + bl_parent_id = 'PHYSICS_PT_settings' + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} - if not PhysicButtonsPanel.poll_fluid_settings(context): + @classmethod + def poll(cls, context): + if not PhysicButtonsPanel.poll_gas_domain(context): return False - return fluid.type in {'DOMAIN', 'FLUID', 'OBSTACLE', 'PARTICLE'} and (context.engine in cls.COMPAT_ENGINES) + + return (context.engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout layout.use_property_split = True md = context.fluid - fluid = md.settings + domain = md.domain_settings - flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding + baked_data = domain.cache_baked_data - if fluid.type not in {'NONE', 'DOMAIN', 'PARTICLE', 'FLUID', 'OBSTACLE'}: - flow.active = fluid.use + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + flow.enabled = not baking_any and not baked_data - if fluid.type == 'DOMAIN': - col = flow.column() + col = flow.column() + col.prop(domain, "alpha") + col.prop(domain, "beta", text="Temperature Diff.") + col = flow.column() + col.prop(domain, "vorticity") - if bpy.app.build_options.openmp: - col.prop(fluid, "threads", text="Simulation Threads") - col.separator() - col.prop(fluid, "resolution", text="Final Resolution") - col.prop(fluid, "preview_resolution", text="Preview") +class PHYSICS_PT_smoke_dissolve(PhysicButtonsPanel, Panel): + bl_label = "Dissolve" + bl_parent_id = 'PHYSICS_PT_smoke' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} - col.separator() + @classmethod + def poll(cls, context): + if not PhysicButtonsPanel.poll_gas_domain(context): + return False - col = flow.column() - col.prop(fluid, "render_display_mode", text="Render Display") - col.prop(fluid, "viewport_display_mode", text="Viewport") + return (context.engine in cls.COMPAT_ENGINES) - col.separator() + def draw_header(self, context): + md = context.fluid + domain = md.domain_settings - col = flow.column() - sub = col.column(align=True) - sub.prop(fluid, "start_time", text="Time Start") - sub.prop(fluid, "end_time", text="End") - col.prop(fluid, "simulation_rate", text="Speed") + self.layout.prop(domain, "use_dissolve_smoke", text="") - col = flow.column() - col.prop(fluid, "use_speed_vectors") - col.prop(fluid, "use_reverse_frames") - col.prop(fluid, "frame_offset", text="Offset") + def draw(self, context): + layout = self.layout + layout.use_property_split = True - elif fluid.type == 'FLUID': - col = flow.column() - col.prop(fluid, "volume_initialization", text="Volume Initialization") - col.prop(fluid, "use_animated_mesh") + md = context.fluid + domain = md.domain_settings - col = flow.column() - col.prop(fluid, "initial_velocity", text="Initial Velocity") + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding + baked_data = domain.cache_baked_data - elif fluid.type == 'OBSTACLE': - col = flow.column() - col.prop(fluid, "volume_initialization", text="Volume Initialization") - col.prop(fluid, "use_animated_mesh") + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + flow.enabled = not baking_any and not baked_data - col = flow.column() - subcol = col.column() - subcol.enabled = not fluid.use_animated_mesh - subcol.prop(fluid, "slip_type", text="Slip Type") + layout.active = domain.use_dissolve_smoke - if fluid.slip_type == 'PARTIALSLIP': - subcol.prop(fluid, "partial_slip_factor", text="Amount", slider=True) + col = flow.column() + col.prop(domain, "dissolve_speed", text="Time") - col.prop(fluid, "impact_factor", text="Impact Factor") + col = flow.column() + col.prop(domain, "use_dissolve_smoke_log", text="Slow") - elif fluid.type == 'PARTICLE': - col = flow.column() - col.prop(fluid, "particle_influence", text="Influence Size") - col.prop(fluid, "alpha_influence", text="Alpha") - col = flow.column() - col.prop(fluid, "use_drops") - col.prop(fluid, "use_floats") - col.prop(fluid, "show_tracer") +class PHYSICS_PT_fire(PhysicButtonsPanel, Panel): + bl_label = "Fire" + bl_parent_id = 'PHYSICS_PT_settings' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + @classmethod + def poll(cls, context): + if not PhysicButtonsPanel.poll_gas_domain(context): + return False -class PHYSICS_PT_fluid_particle_cache(PhysicButtonsPanel, Panel): - bl_label = "Cache" - bl_parent_id = "PHYSICS_PT_fluid" + return (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + md = context.fluid + domain = md.domain_settings + + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding + baked_data = domain.cache_baked_data + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + flow.enabled = not baking_any and not baked_data + + col = flow.column() + col.prop(domain, "burning_rate", text="Reaction Speed") + col = flow.column() + col.prop(domain, "flame_smoke", text="Flame Smoke") + col = flow.column() + col.prop(domain, "flame_vorticity", text="Flame Vorticity") + col = flow.column() + col.prop(domain, "flame_ignition", text="Temperature Ignition") + col = flow.column() + col.prop(domain, "flame_max_temp", text="Maximum Temperature") + col = flow.column() + col.prop(domain, "flame_smoke_color", text="Flame Color") + + +class PHYSICS_PT_liquid(PhysicButtonsPanel, Panel): + bl_label = "Liquid" + bl_parent_id = 'PHYSICS_PT_settings' + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + if not PhysicButtonsPanel.poll_liquid_domain(context): + return False + + return (context.engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + md = context.fluid.domain_settings + self.layout.prop(md, "use_flip_particles", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + md = context.fluid + domain = md.domain_settings + + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding + baked_data = domain.cache_baked_data + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + + col = flow.column() + col0 = col.column() + col0.enabled = not baking_any and not baked_data + col0.prop(domain, "simulation_method", expand=False) + col0.prop(domain, "flip_ratio", text="FLIP Ratio") + col0.prop(domain, "particle_radius", text="Particle Radius") + + col1 = flow.column(align=True) + col1.enabled = not baking_any and not baked_data + col1.prop(domain, "particle_maximum", text="Particles Maximum") + col1.prop(domain, "particle_minimum", text="Minimum") + + col1 = flow.column() + col1.enabled = not baking_any and not baked_data + col1.prop(domain, "particle_number", text="Particle Sampling") + col1.prop(domain, "particle_band_width", text="Narrow Band Width") + col1.prop(domain, "particle_randomness", text="Particle Randomness") + + col2 = flow.column() + col2.enabled = not baking_any and not baked_data + col2.prop(domain, "use_fractions", text="Fractional Obstacles") + col3 = col2.column() + col3.enabled = domain.use_fractions and col2.enabled + col3.prop(domain, "fractions_threshold", text="Obstacle-Fluid Threshold") + + +class PHYSICS_PT_flow_source(PhysicButtonsPanel, Panel): + bl_label = "Flow Source" + bl_parent_id = 'PHYSICS_PT_settings' + bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} @classmethod def poll(cls, context): - if not PhysicButtonsPanel.poll_fluid_settings(context): + if not PhysicButtonsPanel.poll_fluid_flow(context): return False + return (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + ob = context.object + flow = context.fluid.flow_settings + + col = layout.column() + col.prop(flow, "flow_source", expand=False, text="Flow Source") + if flow.flow_source == 'PARTICLES': + col.prop_search(flow, "particle_system", ob, "particle_systems", text="Particle System") + + grid = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + + col = grid.column() + if flow.flow_source == 'MESH': + col.prop(flow, "use_plane_init", text="Is Planar") + col.prop(flow, "surface_distance", text="Surface Thickness") + if flow.flow_type in {'SMOKE', 'BOTH', 'FIRE'}: + col = grid.column() + col.prop(flow, "volume_density", text="Volume Density") + + if flow.flow_source == 'PARTICLES': + col.prop(flow, "use_particle_size", text="Set Size") + sub = col.column() + sub.active = flow.use_particle_size + sub.prop(flow, "particle_size") + + +class PHYSICS_PT_flow_initial_velocity(PhysicButtonsPanel, Panel): + bl_label = "Initial Velocity" + bl_parent_id = 'PHYSICS_PT_settings' + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + if not PhysicButtonsPanel.poll_fluid_flow(context): + return False + + return (context.engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): md = context.fluid - return md and md.settings and (md.settings.type == 'PARTICLE') and (context.engine in cls.COMPAT_ENGINES) + flow_smoke = md.flow_settings + + self.layout.prop(flow_smoke, "use_initial_velocity", text="") def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) + + md = context.fluid + flow_smoke = md.flow_settings + + flow.active = flow_smoke.use_initial_velocity + + col = flow.column() + col.prop(flow_smoke, "velocity_factor") + + if flow_smoke.flow_source == 'MESH': + col.prop(flow_smoke, "velocity_normal") + # col.prop(flow_smoke, "velocity_random") + col = flow.column() + col.prop(flow_smoke, "velocity_coord") + + +class PHYSICS_PT_flow_texture(PhysicButtonsPanel, Panel): + bl_label = "Texture" + bl_parent_id = 'PHYSICS_PT_settings' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + + @classmethod + def poll(cls, context): + if not PhysicButtonsPanel.poll_fluid_flow(context): + return False + + return (context.engine in cls.COMPAT_ENGINES) + def draw_header(self, context): md = context.fluid - fluid = md.settings + flow_smoke = md.flow_settings + + self.layout.prop(flow_smoke, "use_texture", text="") + + 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=False) + + ob = context.object + flow_smoke = context.fluid.flow_settings + + sub = flow.column() + sub.active = flow_smoke.use_texture + sub.prop(flow_smoke, "noise_texture") + sub.prop(flow_smoke, "texture_map_type", text="Mapping") + + col = flow.column() + sub = col.column() + sub.active = flow_smoke.use_texture + + if flow_smoke.texture_map_type == 'UV': + sub.prop_search(flow_smoke, "uv_layer", ob.data, "uv_layers") - layout.prop(fluid, "filepath", text="") + if flow_smoke.texture_map_type == 'AUTO': + sub.prop(flow_smoke, "texture_size") + sub.prop(flow_smoke, "texture_offset") -class PHYSICS_PT_domain_bake(PhysicButtonsPanel, Panel): - bl_label = "Bake" + +class PHYSICS_PT_adaptive_domain(PhysicButtonsPanel, Panel): + bl_label = "Adaptive Domain" + bl_parent_id = 'PHYSICS_PT_fluid' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + if not PhysicButtonsPanel.poll_gas_domain(context): + return False + + return (context.engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + md = context.fluid.domain_settings + domain = context.fluid.domain_settings + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding + self.layout.enabled = not baking_any and not baked_any + self.layout.prop(md, "use_adaptive_domain", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + domain = context.fluid.domain_settings + layout.active = domain.use_adaptive_domain + + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) + flow.enabled = not baking_any and not baked_any + + col = flow.column() + col.prop(domain, "additional_res", text="Add Resolution") + col.prop(domain, "adapt_margin") + + col.separator() + + col = flow.column() + col.prop(domain, "adapt_threshold", text="Threshold") + + +class PHYSICS_PT_noise(PhysicButtonsPanel, Panel): + bl_label = "Noise" bl_parent_id = 'PHYSICS_PT_fluid' bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} @classmethod def poll(cls, context): - if not PhysicButtonsPanel.poll_fluid_domain(context): + if not PhysicButtonsPanel.poll_gas_domain(context): return False return (context.engine in cls.COMPAT_ENGINES) + def draw_header(self, context): + md = context.fluid.domain_settings + domain = context.fluid.domain_settings + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + self.layout.enabled = not baking_any + self.layout.prop(md, "use_noise", text="") + def draw(self, context): layout = self.layout + layout.use_property_split = True - md = context.fluid - fluid = md.settings + domain = context.fluid.domain_settings + + # Deactivate UI if guiding is enabled but not baked yet + layout.active = domain.use_noise and not (domain.use_guiding and not domain.cache_baked_guiding and (domain.guiding_source == "EFFECTOR" or (domain.guiding_source == "DOMAIN" and not domain.guiding_parent))) + + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + baked_noise = domain.cache_baked_noise - row = layout.row(align=True) - row.alignment = 'RIGHT' - row.label(text="Cache Path") + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + flow.enabled = not baking_any and not baked_noise - layout.prop(fluid, "filepath", text="") + col = flow.column() + col.prop(domain, "noise_scale", text="Upres Factor") + # TODO (sebbas): Mantaflow only supports wavelet noise. Maybe get rid of noise type field. + col.prop(domain, "noise_type", text="Noise Method") - # 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() + col.prop(domain, "noise_strength", text="Strength") + col.prop(domain, "noise_pos_scale", text="Scale") + col.prop(domain, "noise_time_anim", text="Time") + if domain.cache_type == "MODULAR": + col.separator() -class PHYSICS_PT_domain_gravity(PhysicButtonsPanel, Panel): - bl_label = "World" + split = layout.split() + split.enabled = domain.cache_baked_data + + bake_incomplete = (domain.cache_frame_pause_noise < domain.cache_frame_end) + if domain.cache_baked_noise and not domain.cache_baking_noise and bake_incomplete: + col = split.column() + col.operator("fluid.bake_noise", text="Resume") + col = split.column() + col.operator("fluid.free_noise", text="Free") + elif not domain.cache_baked_noise and domain.cache_baking_noise: + split.enabled = False + split.operator("fluid.pause_bake", text="Baking Noise - ESC to pause") + elif not domain.cache_baked_noise and not domain.cache_baking_noise: + split.operator("fluid.bake_noise", text="Bake Noise") + else: + split.operator("fluid.free_noise", text="Free Noise") + + +class PHYSICS_PT_mesh(PhysicButtonsPanel, Panel): + bl_label = "Mesh" bl_parent_id = 'PHYSICS_PT_fluid' bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} @classmethod def poll(cls, context): - if not PhysicButtonsPanel.poll_fluid_domain(context): + if not PhysicButtonsPanel.poll_liquid_domain(context): return False return (context.engine in cls.COMPAT_ENGINES) + def draw_header(self, context): + md = context.fluid.domain_settings + domain = context.fluid.domain_settings + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + self.layout.enabled = not baking_any + self.layout.prop(md, "use_mesh", text="") + def draw(self, context): layout = self.layout layout.use_property_split = True - fluid = context.fluid.settings - scene = context.scene + domain = context.fluid.domain_settings - col = layout.column() + # Deactivate UI if guiding is enabled but not baked yet + layout.active = domain.use_mesh and not (domain.use_guiding and not domain.cache_baked_guiding and (domain.guiding_source == "EFFECTOR" or (domain.guiding_source == "DOMAIN" and not domain.guiding_parent))) - use_gravity = scene.use_gravity - use_units = scene.unit_settings.system != 'NONE' + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + baked_mesh = domain.cache_baked_mesh - 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" + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + flow.enabled = not baking_any and not baked_mesh - sub = col.column() - sub.alignment = 'RIGHT' - sub.label(text=warn) + col = flow.column() - flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) + col.prop(domain, "mesh_scale", text="Upres Factor") + col.prop(domain, "mesh_particle_radius", text="Particle Radius") col = flow.column() - sub = col.column() - sub.enabled = not use_gravity - sub.prop(fluid, "gravity", text="Gravity") + col.prop(domain, "use_speed_vectors", text="Use Speed Vectors") - 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.separator() + col.prop(domain, "mesh_generator", text="Mesh Generator") + + if domain.mesh_generator in {'IMPROVED'}: + col = flow.column(align=True) + col.prop(domain, "mesh_smoothen_pos", text="Smoothing Positive") + col.prop(domain, "mesh_smoothen_neg", text="Negative") + + col = flow.column(align=True) + col.prop(domain, "mesh_concave_upper", text="Concavity Upper") + col.prop(domain, "mesh_concave_lower", text="Lower") + + # TODO (sebbas): for now just interpolate any upres grids, ie not sampling highres grids + #col.prop(domain, "highres_sampling", text="Flow Sampling:") + + if domain.cache_type == "MODULAR": + col.separator() + split = layout.split() + split.enabled = domain.cache_baked_data + + bake_incomplete = (domain.cache_frame_pause_mesh < domain.cache_frame_end) + if domain.cache_baked_mesh and not domain.cache_baking_mesh and bake_incomplete: + col = split.column() + col.operator("fluid.bake_mesh", text="Resume") + col = split.column() + col.operator("fluid.free_mesh", text="Free") + elif not domain.cache_baked_mesh and domain.cache_baking_mesh: + split.enabled = False + split.operator("fluid.pause_bake", text="Baking Mesh - ESC to pause") + elif not domain.cache_baked_mesh and not domain.cache_baking_mesh: + split.operator("fluid.bake_mesh", text="Bake Mesh") + else: + split.operator("fluid.free_mesh", text="Free Mesh") + + +class PHYSICS_PT_particles(PhysicButtonsPanel, Panel): + bl_label = "Particles" + bl_parent_id = 'PHYSICS_PT_fluid' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + if not PhysicButtonsPanel.poll_liquid_domain(context): + return False + + return (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + domain = context.fluid.domain_settings + + # Deactivate UI if guiding is enabled but not baked yet + layout.active = not (domain.use_guiding and not domain.cache_baked_guiding and (domain.guiding_source == "EFFECTOR" or (domain.guiding_source == "DOMAIN" and not domain.guiding_parent))) + + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + baked_particles = domain.cache_baked_particles + using_particles = domain.use_spray_particles or domain.use_foam_particles or domain.use_bubble_particles + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + flow.enabled = not baking_any + + subSpray = flow.column() + subSpray.enabled = (domain.sndparticle_combined_export == 'OFF') or (domain.sndparticle_combined_export == 'FOAM + BUBBLES') + subSpray.prop(domain, "use_spray_particles", text="Spray") + subFoam = flow.column() + subFoam.enabled = (domain.sndparticle_combined_export == 'OFF') or (domain.sndparticle_combined_export == 'SPRAY + BUBBLES') + subFoam.prop(domain, "use_foam_particles", text="Foam") + subBubbles = flow.column() + subBubbles.enabled = (domain.sndparticle_combined_export == 'OFF') or (domain.sndparticle_combined_export == 'SPRAY + FOAM') + subBubbles.prop(domain, "use_bubble_particles", text="Bubbles") + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + flow.enabled = not baking_any and not baked_particles and using_particles + + col = flow.column() + col.prop(domain, "sndparticle_combined_export") + col.prop(domain, "particle_scale", text="Upres Factor") + col.separator() + + col = flow.column(align=True) + col.prop(domain, "sndparticle_tau_max_wc", text="Wave Crest Potential Maximum") + col.prop(domain, "sndparticle_tau_min_wc", text="Minimum") + col.separator() + + col = flow.column(align=True) + col.prop(domain, "sndparticle_tau_max_ta", text="Trapped Air Potential Maximum") + col.prop(domain, "sndparticle_tau_min_ta", text="Minimum") + col.separator() + + col = flow.column(align=True) + col.prop(domain, "sndparticle_tau_max_k", text="Kinetic Energy Potential Maximum") + col.prop(domain, "sndparticle_tau_min_k", text="Minimum") + col.separator() + + col = flow.column(align=True) + col.prop(domain, "sndparticle_potential_radius", text="Potential Radius") + col.prop(domain, "sndparticle_update_radius", text="Particle Update Radius") + col.separator() + + col = flow.column(align=True) + col.prop(domain, "sndparticle_k_wc", text="Wave Crest Particle Sampling") + col.prop(domain, "sndparticle_k_ta", text="Trapped Air Particle Sampling") + col.separator() + + col = flow.column(align=True) + col.prop(domain, "sndparticle_l_max", text="Particle Life Maximum") + col.prop(domain, "sndparticle_l_min", text="Minimum") + col.separator() + + col = flow.column(align=True) + col.prop(domain, "sndparticle_k_b", text="Bubble Buoyancy") + col.prop(domain, "sndparticle_k_d", text="Bubble Drag") col.separator() col = flow.column() - col.prop(fluid, "grid_levels", text="Optimization", slider=True) - col.prop(fluid, "compressibility", slider=True) + col.prop(domain, "sndparticle_boundary", text="Particles in Boundary:") + if domain.cache_type == "MODULAR": + col.separator() -class PHYSICS_PT_domain_viscosity(PhysicButtonsPanel, Panel): - bl_label = "Viscosity" + split = layout.split() + split.enabled = domain.cache_baked_data and (domain.use_spray_particles or domain.use_bubble_particles or domain.use_foam_particles or domain.use_tracer_particles) + + bake_incomplete = (domain.cache_frame_pause_particles < domain.cache_frame_end) + if domain.cache_baked_particles and not domain.cache_baking_particles and bake_incomplete: + col = split.column() + col.operator("fluid.bake_particles", text="Resume") + col = split.column() + col.operator("fluid.free_particles", text="Free") + elif not domain.cache_baked_particles and domain.cache_baking_particles: + split.enabled = False + split.operator("fluid.pause_bake", text="Baking Particles - ESC to pause") + elif not domain.cache_baked_particles and not domain.cache_baking_particles: + split.operator("fluid.bake_particles", text="Bake Particles") + else: + split.operator("fluid.free_particles", text="Free Particles") + + +class PHYSICS_PT_diffusion(PhysicButtonsPanel, Panel): + bl_label = "Diffusion" bl_parent_id = 'PHYSICS_PT_fluid' bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} @classmethod def poll(cls, context): + # Fluid diffusion only enabled for liquids (surface tension and viscosity not relevant for smoke) + if not PhysicButtonsPanel.poll_liquid_domain(context): + return False + + return (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + domain = context.fluid.domain_settings + + # Deactivate UI if guiding is enabled but not baked yet + layout.active = not (domain.use_guiding and not domain.cache_baked_guiding and (domain.guiding_source == "EFFECTOR" or (domain.guiding_source == "DOMAIN" and not domain.guiding_parent))) + + split = layout.split() + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding + baked_data = domain.cache_baked_data + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + flow.enabled = not baking_any and not baked_any and not baked_data + + row = flow.row() + + col = row.column() + col.label(text="Viscosity Presets:") + col.menu("FLUID_MT_presets", text=bpy.types.FLUID_MT_presets.bl_label) + + col = row.column(align=True) + col.operator("fluid.preset_add", text="", icon='ADD') + col.operator("fluid.preset_add", text="", icon='REMOVE').remove_active = True + + col = flow.column(align=True) + col.prop(domain, "viscosity_base", text="Base") + col.prop(domain, "viscosity_exponent", text="Exponent", slider=True) + + col = flow.column() + col.prop(domain, "domain_size", text="Real World Size") + col.prop(domain, "surface_tension", text="Surface Tension") + + +class PHYSICS_PT_guiding(PhysicButtonsPanel, Panel): + bl_label = "Guiding" + bl_parent_id = 'PHYSICS_PT_fluid' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @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_header(self, context): + md = context.fluid.domain_settings + domain = context.fluid.domain_settings + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + self.layout.enabled = not baking_any + self.layout.prop(md, "use_guiding", text="") 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 + domain = context.fluid.domain_settings + + layout.active = domain.use_guiding + + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + baked_data = domain.cache_baked_data + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + flow.enabled = not baking_any and not baked_data col = flow.column() - col.prop(fluid, "viscosity_base", text="Base") + col.prop(domain, "guiding_alpha", text="Weight") + col.prop(domain, "guiding_beta", text="Size") + col.prop(domain, "guiding_vel_factor", text="Velocity Factor") col = flow.column() - col.prop(fluid, "viscosity_exponent", text="Exponent", slider=True) + col.prop(domain, "guiding_source", text="Velocity Source") + if domain.guiding_source == "DOMAIN": + col.prop(domain, "guiding_parent", text="Guiding Parent") + if domain.cache_type == "MODULAR": + col.separator() -class PHYSICS_PT_domain_boundary(PhysicButtonsPanel, Panel): - bl_label = "Boundary" + if domain.guiding_source == "EFFECTOR": + split = layout.split() + bake_incomplete = (domain.cache_frame_pause_guiding < domain.cache_frame_end) + if domain.cache_baked_guiding and not domain.cache_baking_guiding and bake_incomplete: + col = split.column() + col.operator("fluid.bake_guiding", text="Resume") + col = split.column() + col.operator("fluid.free_guiding", text="Free") + elif not domain.cache_baked_guiding and domain.cache_baking_guiding: + split.operator("fluid.pause_bake", text="Pause Guiding") + elif not domain.cache_baked_guiding and not domain.cache_baking_guiding: + split.operator("fluid.bake_guiding", text="Bake Guiding") + else: + split.operator("fluid.free_guiding", text="Free Guiding") + + +class PHYSICS_PT_collections(PhysicButtonsPanel, Panel): + bl_label = "Collections" bl_parent_id = 'PHYSICS_PT_fluid' bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} @@ -403,26 +1001,127 @@ class PHYSICS_PT_domain_boundary(PhysicButtonsPanel, Panel): 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 + domain = context.fluid.domain_settings + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + + col = flow.column() + col.prop(domain, "fluid_group", text="Flow") + + # col.prop(domain, "effector_group", text="Forces") + col.prop(domain, "effector_group", text="Effector") + + +class PHYSICS_PT_cache(PhysicButtonsPanel, Panel): + bl_label = "Cache" + bl_parent_id = 'PHYSICS_PT_fluid' + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + + @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 + domain = context.fluid.domain_settings + + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding + + col = layout.column() + col.prop(domain, "cache_directory", text="") + col.enabled = not baking_any + + layout.use_property_split = True + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) col = flow.column() - col.prop(fluid, "slip_type", text="Type") + col.prop(domain, "cache_type", expand=False) + col.enabled = not baking_any + col = flow.column(align=True) col.separator() - if fluid.slip_type == 'PARTIALSLIP': - col.prop(fluid, "partial_slip_factor", slider=True, text="Amount") + col.prop(domain, "cache_frame_start", text="Frame Start") + col.prop(domain, "cache_frame_end", text="End") + col.enabled = not baking_any + + col.separator() col = flow.column() - col.prop(fluid, "surface_smooth", text="Surface Smoothing") - col.prop(fluid, "surface_subdivisions", text="Subdivisions") - col.prop(fluid, "use_surface_noobs") + col.enabled = not baking_any and not baked_any + col.prop(domain, "cache_data_format", text="Data File Format") + if md.domain_settings.domain_type in {'GAS'}: + if domain.use_noise: + col.prop(domain, "cache_noise_format", text="Noise File Format") -class PHYSICS_PT_domain_particles(PhysicButtonsPanel, Panel): - bl_label = "Particles" + if md.domain_settings.domain_type in {'LIQUID'}: + # File format for all particle systemes (FLIP and secondary) + col.prop(domain, "cache_particle_format", text="Particle File Format") + + if domain.use_mesh: + col.prop(domain, "cache_mesh_format", text="Mesh File Format") + + if domain.cache_type == "FINAL": + + col.separator() + split = layout.split() + + bake_incomplete = (domain.cache_frame_pause_data < domain.cache_frame_end) + if domain.cache_baked_data and not domain.cache_baking_data and bake_incomplete: + col = split.column() + col.operator("fluid.bake_all", text="Resume") + col = split.column() + col.operator("fluid.free_all", text="Free") + elif domain.cache_baking_data and not domain.cache_baked_data: + split.enabled = False + split.operator("fluid.pause_bake", text="Baking All - ESC to pause") + elif not domain.cache_baked_data and not domain.cache_baking_data: + split.operator("fluid.bake_all", text="Bake All") + else: + split.operator("fluid.free_all", text="Free All") + + +class PHYSICS_PT_export(PhysicButtonsPanel, Panel): + bl_label = "Advanced" + bl_parent_id = 'PHYSICS_PT_cache' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + + @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 + layout.use_property_split = True + + md = context.fluid + domain = context.fluid.domain_settings + + baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding + baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + flow.enabled = not baking_any and not baked_any + + col = flow.column() + col.prop(domain, "export_manta_script", text="Export Mantaflow Script") + + +class PHYSICS_PT_field_weights(PhysicButtonsPanel, Panel): + bl_label = "Field Weights" bl_parent_id = 'PHYSICS_PT_fluid' bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} @@ -435,32 +1134,141 @@ class PHYSICS_PT_domain_particles(PhysicButtonsPanel, Panel): return (context.engine in cls.COMPAT_ENGINES) def draw(self, context): + domain = context.fluid.domain_settings + effector_weights_ui(self, domain.effector_weights, 'SMOKE') + + +class PHYSICS_PT_viewport_display(PhysicButtonsPanel, Panel): + bl_label = "Viewport Display" + bl_parent_id = 'PHYSICS_PT_fluid' + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + return (PhysicButtonsPanel.poll_gas_domain(context)) + + 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 + domain = context.fluid.domain_settings col = flow.column() - col.prop(fluid, "tracer_particles", text="Tracer") + col.prop(domain, "display_thickness") + + col.separator() + + col.prop(domain, "slice_method", text="Slicing") + + slice_method = domain.slice_method + axis_slice_method = domain.axis_slice_method + + do_axis_slicing = (slice_method == 'AXIS_ALIGNED') + do_full_slicing = (axis_slice_method == 'FULL') + + col = col.column() + col.enabled = do_axis_slicing + col.prop(domain, "axis_slice_method") + + col = flow.column() + sub = col.column() + sub.enabled = not do_full_slicing and do_axis_slicing + sub.prop(domain, "slice_axis") + sub.prop(domain, "slice_depth") + + row = col.row() + row.enabled = do_full_slicing or not do_axis_slicing + row.prop(domain, "slice_per_voxel") + + col.prop(domain, "display_interpolation") + + +class PHYSICS_PT_viewport_display_color(PhysicButtonsPanel, Panel): + bl_label = "Color Mapping" + bl_parent_id = 'PHYSICS_PT_viewport_display' + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + return (PhysicButtonsPanel.poll_gas_domain(context)) + + def draw_header(self, context): + md = context.fluid.domain_settings + + self.layout.prop(md, "use_color_ramp", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + domain = context.fluid.domain_settings + col = layout.column() + col.enabled = domain.use_color_ramp + + col.prop(domain, "coba_field") + + col.use_property_split = False + + col = col.column() + col.template_color_ramp(domain, "color_ramp", expand=True) + + +class PHYSICS_PT_viewport_display_debug(PhysicButtonsPanel, Panel): + bl_label = "Debug Velocity" + bl_parent_id = 'PHYSICS_PT_viewport_display' + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + return (PhysicButtonsPanel.poll_gas_domain(context)) + + def draw_header(self, context): + md = context.fluid.domain_settings + + self.layout.prop(md, "show_velocity", text="") + + 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) + + domain = context.fluid.domain_settings col = flow.column() - col.prop(fluid, "generate_particles", text="Generate") + col.enabled = domain.show_velocity + col.prop(domain, "vector_display_type", text="Display As") + col.prop(domain, "vector_scale") classes = ( - FLUID_PT_presets, + FLUID_MT_presets, PHYSICS_PT_fluid, - PHYSICS_PT_fluid_settings, - PHYSICS_PT_fluid_flow, - 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, + PHYSICS_PT_settings, + PHYSICS_PT_borders, + PHYSICS_PT_smoke, + PHYSICS_PT_smoke_dissolve, + PHYSICS_PT_fire, + PHYSICS_PT_liquid, + PHYSICS_PT_flow_source, + PHYSICS_PT_flow_initial_velocity, + PHYSICS_PT_flow_texture, + PHYSICS_PT_adaptive_domain, + PHYSICS_PT_noise, + PHYSICS_PT_mesh, + PHYSICS_PT_particles, + PHYSICS_PT_diffusion, + PHYSICS_PT_guiding, + PHYSICS_PT_collections, + PHYSICS_PT_cache, + PHYSICS_PT_export, + PHYSICS_PT_field_weights, + PHYSICS_PT_viewport_display, + PHYSICS_PT_viewport_display_color, + PHYSICS_PT_viewport_display_debug, ) + if __name__ == "__main__": # only for live edit. from bpy.utils import register_class for cls in classes: diff --git a/release/scripts/startup/bl_ui/properties_physics_smoke.py b/release/scripts/startup/bl_ui/properties_physics_smoke.py deleted file mode 100644 index 057e7ddf211..00000000000 --- a/release/scripts/startup/bl_ui/properties_physics_smoke.py +++ /dev/null @@ -1,692 +0,0 @@ -# ##### BEGIN GPL LICENSE BLOCK ##### -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -# <pep8 compliant> - -import bpy -from bpy.types import ( - Panel, -) -from bl_ui.properties_physics_common import ( - point_cache_ui, - effector_weights_ui, -) - - -class PhysicButtonsPanel: - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "physics" - - @staticmethod - def poll_smoke(context): - ob = context.object - if not ((ob and ob.type == 'MESH') and (context.smoke)): - return False - - md = context.smoke - return md and (context.smoke.smoke_type != 'NONE') and (bpy.app.build_options.mod_smoke) - - @staticmethod - def poll_smoke_domain(context): - if not PhysicButtonsPanel.poll_smoke(context): - return False - - md = context.smoke - return md and (md.smoke_type == 'DOMAIN') - - -class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel): - bl_label = "Smoke" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} - - @classmethod - def poll(cls, context): - ob = context.object - return (ob and ob.type == 'MESH') and (context.engine in cls.COMPAT_ENGINES) and (context.smoke) - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - - if not bpy.app.build_options.mod_smoke: - col = layout.column(align=True) - col.alignment = 'RIGHT' - col.label(text="Built without Smoke modifier") - return - - md = context.smoke - - layout.prop(md, "smoke_type") - - -class PHYSICS_PT_smoke_settings(PhysicButtonsPanel, Panel): - bl_label = "Settings" - bl_parent_id = 'PHYSICS_PT_smoke' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} - - @classmethod - def poll(cls, context): - if not PhysicButtonsPanel.poll_smoke(context): - return False - - return (context.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - - md = context.smoke - ob = context.object - - if md.smoke_type == 'DOMAIN': - domain = md.domain_settings - - flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) - - col = flow.column() - col.enabled = (not domain.point_cache.is_baked) - col.prop(domain, "resolution_max", text="Resolution Divisions") - col.prop(domain, "time_scale", text="Time Scale") - - col.separator() - - col = flow.column() - sub = col.row() - sub.enabled = (not domain.point_cache.is_baked) - sub.prop(domain, "collision_extents", text="Border Collisions") - - # This can be tweaked after baking, for render. - col.prop(domain, "clipping", text="Empty Space") - - elif md.smoke_type == 'FLOW': - flow_smoke = md.flow_settings - - col = layout.column() - col.prop(flow_smoke, "smoke_flow_type", expand=False) - - col.separator() - - flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) - col = flow.column() - - if flow_smoke.smoke_flow_type != 'OUTFLOW': - col.prop(flow_smoke, "smoke_flow_source", expand=False, text="Flow Source") - - if flow_smoke.smoke_flow_source == 'PARTICLES': - col.prop_search( - flow_smoke, "particle_system", ob, "particle_systems", - text="Particle System" - ) - else: - col.prop(flow_smoke, "surface_distance") - col.prop(flow_smoke, "volume_density") - - col = flow.column() - col.prop(flow_smoke, "use_absolute") - - if flow_smoke.smoke_flow_type in {'SMOKE', 'BOTH'}: - col.prop(flow_smoke, "density") - col.prop(flow_smoke, "temperature", text="Temperature Diff.") - - col.separator() - - col = flow.column() - col.prop(flow_smoke, "smoke_color") - - if flow_smoke.smoke_flow_type in {'FIRE', 'BOTH'}: - col.prop(flow_smoke, "fuel_amount") - - col.prop(flow_smoke, "subframes", text="Sampling Subframes") - - col.separator() - - col.prop_search(flow_smoke, "density_vertex_group", ob, "vertex_groups", text="Vertex Group") - - elif md.smoke_type == 'COLLISION': - coll = md.coll_settings - - col = layout.column() - col.prop(coll, "collision_type") - - -class PHYSICS_PT_smoke_settings_initial_velocity(PhysicButtonsPanel, Panel): - bl_label = "Initial Velocity" - bl_parent_id = 'PHYSICS_PT_smoke_settings' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} - - @classmethod - def poll(cls, context): - if not PhysicButtonsPanel.poll_smoke(context): - return False - - md = context.smoke - return (md and (md.smoke_type == 'FLOW') - and md.flow_settings and md.flow_settings.smoke_flow_type != 'OUTFLOW' - and context.engine in cls.COMPAT_ENGINES) - - def draw_header(self, context): - md = context.smoke - flow_smoke = md.flow_settings - - self.layout.prop(flow_smoke, "use_initial_velocity", text="") - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) - - md = context.smoke - flow_smoke = md.flow_settings - - flow.active = flow_smoke.use_initial_velocity - - col = flow.column(align=True) - col.prop(flow_smoke, "velocity_factor") - - if flow_smoke.smoke_flow_source == 'MESH': - col = flow.column() - col.prop(flow_smoke, "velocity_normal") - # sub.prop(flow_smoke, "velocity_random") - - -class PHYSICS_PT_smoke_settings_particle_size(PhysicButtonsPanel, Panel): - bl_label = "Particle Size" - bl_parent_id = 'PHYSICS_PT_smoke_settings' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} - - @classmethod - def poll(cls, context): - if not PhysicButtonsPanel.poll_smoke(context): - return False - - md = context.smoke - return (md and (md.smoke_type == 'FLOW') - and md.flow_settings and md.flow_settings.smoke_flow_type != 'OUTFLOW' - and md.flow_settings.smoke_flow_source == 'PARTICLES' - and context.engine in cls.COMPAT_ENGINES) - - def draw_header(self, context): - md = context.smoke - flow_smoke = md.flow_settings - - self.layout.prop(flow_smoke, "use_particle_size", text="") - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - - md = context.smoke - flow_smoke = md.flow_settings - - layout.active = flow_smoke.use_particle_size - - layout.prop(flow_smoke, "particle_size") - - -class PHYSICS_PT_smoke_behavior(PhysicButtonsPanel, Panel): - bl_label = "Behavior" - bl_parent_id = 'PHYSICS_PT_smoke_settings' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} - - @classmethod - def poll(cls, context): - if not PhysicButtonsPanel.poll_smoke_domain(context): - return False - - return (context.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - - md = context.smoke - domain = md.domain_settings - - flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) - flow.enabled = (not domain.point_cache.is_baked) - - col = flow.column() - col.prop(domain, "alpha") - col.prop(domain, "beta", text="Temperature Diff.") - col = flow.column() - col.prop(domain, "vorticity") - - -class PHYSICS_PT_smoke_behavior_dissolve(PhysicButtonsPanel, Panel): - bl_label = "Dissolve" - bl_parent_id = 'PHYSICS_PT_smoke_behavior' - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} - - @classmethod - def poll(cls, context): - if not PhysicButtonsPanel.poll_smoke_domain(context): - return False - - return (context.engine in cls.COMPAT_ENGINES) - - def draw_header(self, context): - md = context.smoke - domain = md.domain_settings - - self.layout.prop(domain, "use_dissolve_smoke", text="") - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - - md = context.smoke - domain = md.domain_settings - - flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) - flow.enabled = (not domain.point_cache.is_baked) - - layout.active = domain.use_dissolve_smoke - - col = flow.column() - col.prop(domain, "dissolve_speed", text="Time") - - col = flow.column() - col.prop(domain, "use_dissolve_smoke_log", text="Slow") - - -class PHYSICS_PT_smoke_flow_texture(PhysicButtonsPanel, Panel): - bl_label = "Texture" - bl_parent_id = 'PHYSICS_PT_smoke' - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} - - @classmethod - def poll(cls, context): - if not PhysicButtonsPanel.poll_smoke(context): - return False - - md = context.smoke - return (md and (md.smoke_type == 'FLOW') - and (md.flow_settings.smoke_flow_source == 'MESH') - and (context.engine in cls.COMPAT_ENGINES)) - - def draw_header(self, context): - md = context.smoke - flow_smoke = md.flow_settings - - self.layout.prop(flow_smoke, "use_texture", text="") - - 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=False) - - ob = context.object - flow_smoke = context.smoke.flow_settings - - sub = flow.column() - sub.active = flow_smoke.use_texture - sub.prop(flow_smoke, "noise_texture") - sub.prop(flow_smoke, "texture_map_type", text="Mapping") - - col = flow.column() - sub = col.column() - sub.active = flow_smoke.use_texture - - if flow_smoke.texture_map_type == 'UV': - sub.prop_search(flow_smoke, "uv_layer", ob.data, "uv_layers") - - if flow_smoke.texture_map_type == 'AUTO': - sub.prop(flow_smoke, "texture_size") - - sub.prop(flow_smoke, "texture_offset") - - -class PHYSICS_PT_smoke_fire(PhysicButtonsPanel, Panel): - bl_label = "Flames" - bl_parent_id = 'PHYSICS_PT_smoke' - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} - - @classmethod - def poll(cls, context): - if not PhysicButtonsPanel.poll_smoke_domain(context): - return False - - return (context.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - - domain = context.smoke.domain_settings - - flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) - flow.enabled = (not domain.point_cache.is_baked) - - col = flow.column() - col.prop(domain, "burning_rate", text="Reaction Speed") - col.prop(domain, "flame_smoke") - col.prop(domain, "flame_vorticity") - - col.separator() - - col = flow.column(align=True) - col.prop(domain, "flame_ignition", text="Temperature Ignition") - col.prop(domain, "flame_max_temp") - - col.separator() - - sub = col.column() - sub.prop(domain, "flame_smoke_color") - - -class PHYSICS_PT_smoke_adaptive_domain(PhysicButtonsPanel, Panel): - bl_label = "Adaptive Domain" - bl_parent_id = 'PHYSICS_PT_smoke' - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} - - @classmethod - def poll(cls, context): - if not PhysicButtonsPanel.poll_smoke_domain(context): - return False - - return (context.engine in cls.COMPAT_ENGINES) - - def draw_header(self, context): - md = context.smoke.domain_settings - - self.layout.prop(md, "use_adaptive_domain", text="") - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - - domain = context.smoke.domain_settings - layout.active = domain.use_adaptive_domain - - flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) - flow.enabled = (not domain.point_cache.is_baked) - - col = flow.column() - col.prop(domain, "additional_res", text="Add Resolution") - col.prop(domain, "adapt_margin") - - col.separator() - - col = flow.column() - col.prop(domain, "adapt_threshold", text="Threshold") - - -class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, Panel): - bl_label = "High Resolution" - bl_parent_id = 'PHYSICS_PT_smoke' - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} - - @classmethod - def poll(cls, context): - if not PhysicButtonsPanel.poll_smoke_domain(context): - return False - - return (context.engine in cls.COMPAT_ENGINES) - - def draw_header(self, context): - md = context.smoke.domain_settings - - self.layout.prop(md, "use_high_resolution", text="") - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - - md = context.smoke.domain_settings - layout.active = md.use_high_resolution - - flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) - - col = flow.column() - col.enabled = not md.point_cache.is_baked - col.prop(md, "amplify", text="Resolution Divisions") - col.prop(md, "highres_sampling", text="Flow Sampling") - - col.separator() - - col = flow.column() - col.enabled = not md.point_cache.is_baked - col.prop(md, "noise_type", text="Noise Method") - col.prop(md, "strength") - - layout.prop(md, "show_high_resolution") - - -class PHYSICS_PT_smoke_collections(PhysicButtonsPanel, Panel): - bl_label = "Collections" - bl_parent_id = 'PHYSICS_PT_smoke' - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} - - @classmethod - def poll(cls, context): - if not PhysicButtonsPanel.poll_smoke_domain(context): - return False - - return (context.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - - domain = context.smoke.domain_settings - - col = layout.column() - col.prop(domain, "fluid_collection", text="Flow") - - # col = layout.column() - # col.prop(domain, "effector_collection", text="Effector") - col.prop(domain, "collision_collection", text="Collision") - - -class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel): - bl_label = "Cache" - bl_parent_id = 'PHYSICS_PT_smoke' - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} - - @classmethod - def poll(cls, context): - if not PhysicButtonsPanel.poll_smoke_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) - - domain = context.smoke.domain_settings - cache_file_format = domain.cache_file_format - - col = flow.column() - col.prop(domain, "cache_file_format") - - if cache_file_format == 'POINTCACHE': - col = flow.column() - col.prop(domain, "point_cache_compress_type", text="Compression") - col.separator() - - elif cache_file_format == 'OPENVDB': - if not bpy.app.build_options.openvdb: - row = layout.row(align=True) - row.alignment = 'RIGHT' - row.label(text="Built without OpenVDB support") - return - - col = flow.column() - col.prop(domain, "openvdb_cache_compress_type", text="Compression") - col.prop(domain, "data_depth", text="Data Depth") - col.separator() - - cache = domain.point_cache - point_cache_ui(self, cache, (cache.is_baked is False), 'SMOKE') - - -class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel, Panel): - bl_label = "Field Weights" - bl_parent_id = 'PHYSICS_PT_smoke' - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} - - @classmethod - def poll(cls, context): - if not PhysicButtonsPanel.poll_smoke_domain(context): - return False - - return (context.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - domain = context.smoke.domain_settings - effector_weights_ui(self, domain.effector_weights, 'SMOKE') - - -class PHYSICS_PT_smoke_viewport_display(PhysicButtonsPanel, Panel): - bl_label = "Viewport Display" - bl_parent_id = 'PHYSICS_PT_smoke' - bl_options = {'DEFAULT_CLOSED'} - - @classmethod - def poll(cls, context): - return (PhysicButtonsPanel.poll_smoke_domain(context)) - - 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) - - domain = context.smoke.domain_settings - - col = flow.column() - col.prop(domain, "display_thickness") - - col.separator() - - col.prop(domain, "slice_method", text="Slicing") - - slice_method = domain.slice_method - axis_slice_method = domain.axis_slice_method - - do_axis_slicing = (slice_method == 'AXIS_ALIGNED') - do_full_slicing = (axis_slice_method == 'FULL') - - col = col.column() - col.enabled = do_axis_slicing - col.prop(domain, "axis_slice_method") - - col = flow.column() - sub = col.column() - sub.enabled = not do_full_slicing and do_axis_slicing - sub.prop(domain, "slice_axis") - sub.prop(domain, "slice_depth") - - row = col.row() - row.enabled = do_full_slicing or not do_axis_slicing - row.prop(domain, "slice_per_voxel") - - col.prop(domain, "display_interpolation") - - -class PHYSICS_PT_smoke_viewport_display_color(PhysicButtonsPanel, Panel): - bl_label = "Color Mapping" - bl_parent_id = 'PHYSICS_PT_smoke_viewport_display' - bl_options = {'DEFAULT_CLOSED'} - - @classmethod - def poll(cls, context): - return (PhysicButtonsPanel.poll_smoke_domain(context)) - - def draw_header(self, context): - md = context.smoke.domain_settings - - self.layout.prop(md, "use_color_ramp", text="") - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - - domain = context.smoke.domain_settings - col = layout.column() - col.enabled = domain.use_color_ramp - - col.prop(domain, "coba_field") - - col.use_property_split = False - - col = col.column() - col.template_color_ramp(domain, "color_ramp", expand=True) - - -class PHYSICS_PT_smoke_viewport_display_debug(PhysicButtonsPanel, Panel): - bl_label = "Debug Velocity" - bl_parent_id = 'PHYSICS_PT_smoke_viewport_display' - bl_options = {'DEFAULT_CLOSED'} - - @classmethod - def poll(cls, context): - return (PhysicButtonsPanel.poll_smoke_domain(context)) - - def draw_header(self, context): - md = context.smoke.domain_settings - - self.layout.prop(md, "show_velocity", text="") - - 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) - - domain = context.smoke.domain_settings - - col = flow.column() - col.enabled = domain.show_velocity - col.prop(domain, "vector_display_type", text="Display As") - col.prop(domain, "vector_scale") - - -classes = ( - PHYSICS_PT_smoke, - PHYSICS_PT_smoke_settings, - PHYSICS_PT_smoke_settings_initial_velocity, - PHYSICS_PT_smoke_settings_particle_size, - PHYSICS_PT_smoke_behavior, - PHYSICS_PT_smoke_behavior_dissolve, - PHYSICS_PT_smoke_adaptive_domain, - PHYSICS_PT_smoke_cache, - PHYSICS_PT_smoke_field_weights, - PHYSICS_PT_smoke_fire, - PHYSICS_PT_smoke_flow_texture, - PHYSICS_PT_smoke_collections, - PHYSICS_PT_smoke_highres, - PHYSICS_PT_smoke_viewport_display, - PHYSICS_PT_smoke_viewport_display_color, - PHYSICS_PT_smoke_viewport_display_debug, -) - - -if __name__ == "__main__": # only for live edit. - from bpy.utils import register_class - for cls in classes: - register_class(cls) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 2fb8afbbd23..3aecd7b9775 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -2195,7 +2195,6 @@ class USERPREF_PT_experimental_ui(ExperimentalPanel, Panel): col = split.column() col.operator("wm.url_open", text=task, icon='URL').url = self.url_prefix + task - """ # Example panel, leave it here so we always have a template to follow even # after the features are gone from the experimental panel. diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 596b7b13e05..6374b3af46d 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -2647,7 +2647,7 @@ class VIEW3D_MT_object_quick_effects(Menu): layout.operator("object.quick_fur") layout.operator("object.quick_explode") layout.operator("object.quick_smoke") - layout.operator("object.quick_fluid") + layout.operator("object.quick_liquid") class VIEW3D_MT_object_showhide(Menu): |