properties_physics_fluid.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. # ##### BEGIN GPL LICENSE BLOCK #####
  2. #
  3. # This program is free software; you can redistribute it and/or
  4. # modify it under the terms of the GNU General Public License
  5. # as published by the Free Software Foundation; either version 2
  6. # of the License, or (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program; if not, write to the Free Software Foundation,
  15. # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  16. #
  17. # ##### END GPL LICENSE BLOCK #####
  18. # <pep8 compliant>
  19. import bpy
  20. from bpy.types import (
  21. Panel,
  22. )
  23. from bpy.app.translations import pgettext_iface as iface_
  24. from bl_ui.utils import PresetPanel
  25. class FLUID_PT_presets(PresetPanel, Panel):
  26. bl_label = "Fluid Presets"
  27. preset_subdir = "fluid"
  28. preset_operator = "script.execute_preset"
  29. preset_add_operator = "fluid.preset_add"
  30. class PhysicButtonsPanel:
  31. bl_space_type = 'PROPERTIES'
  32. bl_region_type = 'WINDOW'
  33. bl_context = "physics"
  34. @staticmethod
  35. def poll_fluid(context):
  36. ob = context.object
  37. if not ((ob and ob.type == 'MESH') and (context.fluid)):
  38. return False
  39. return (bpy.app.build_options.mod_fluid)
  40. @staticmethod
  41. def poll_fluid_settings(context):
  42. if not (PhysicButtonsPanel.poll_fluid(context)):
  43. return False
  44. md = context.fluid
  45. return md and md.settings and (md.settings.type != 'NONE')
  46. @staticmethod
  47. def poll_fluid_domain(context):
  48. if not PhysicButtonsPanel.poll_fluid(context):
  49. return False
  50. md = context.fluid
  51. return md and md.settings and (md.settings.type == 'DOMAIN')
  52. class PHYSICS_PT_fluid(PhysicButtonsPanel, Panel):
  53. bl_label = "Fluid"
  54. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
  55. @classmethod
  56. def poll(cls, context):
  57. ob = context.object
  58. return (ob and ob.type == 'MESH') and context.engine in cls.COMPAT_ENGINES and (context.fluid)
  59. def draw(self, context):
  60. layout = self.layout
  61. layout.use_property_split = True
  62. if not bpy.app.build_options.mod_fluid:
  63. col = layout.column()
  64. col.alignment = 'RIGHT'
  65. col.label(text="Built without fluids")
  66. return
  67. md = context.fluid
  68. fluid = md.settings
  69. col = layout.column()
  70. col.prop(fluid, "type")
  71. class PHYSICS_PT_fluid_flow(PhysicButtonsPanel, Panel):
  72. bl_label = "Flow"
  73. bl_parent_id = "PHYSICS_PT_fluid"
  74. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
  75. @classmethod
  76. def poll(cls, context):
  77. md = context.fluid
  78. fluid = md.settings
  79. if not PhysicButtonsPanel.poll_fluid_settings(context):
  80. return False
  81. return fluid.type in {'INFLOW', 'OUTFLOW', 'CONTROL'} and (context.engine in cls.COMPAT_ENGINES)
  82. def draw_header(self, context):
  83. md = context.fluid
  84. fluid = md.settings
  85. self.layout.prop(fluid, "use", text="")
  86. def draw(self, context):
  87. layout = self.layout
  88. layout.use_property_split = True
  89. md = context.fluid
  90. fluid = md.settings
  91. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
  92. flow.active = fluid.use
  93. if fluid.type == 'INFLOW':
  94. col = flow.column()
  95. col.prop(fluid, "volume_initialization", text="Volume Initialization")
  96. col.prop(fluid, "use_animated_mesh")
  97. row = col.row()
  98. row.active = not fluid.use_animated_mesh
  99. row.prop(fluid, "use_local_coords")
  100. col = flow.column()
  101. col.prop(fluid, "inflow_velocity", text="Inflow Velocity")
  102. elif fluid.type == 'OUTFLOW':
  103. col = flow.column()
  104. col.prop(fluid, "volume_initialization", text="Volume Initialization")
  105. col = flow.column()
  106. col.prop(fluid, "use_animated_mesh")
  107. elif fluid.type == 'CONTROL':
  108. col = flow.column()
  109. col.prop(fluid, "quality", slider=True)
  110. col.prop(fluid, "use_reverse_frames")
  111. col = flow.column()
  112. col.prop(fluid, "start_time", text="Time Start")
  113. col.prop(fluid, "end_time", text="End")
  114. col.separator()
  115. col = flow.column()
  116. col.prop(fluid, "attraction_strength", text="Attraction Strength")
  117. col.prop(fluid, "attraction_radius", text="Radius")
  118. col.separator()
  119. col = flow.column(align=True)
  120. col.prop(fluid, "velocity_strength", text="Velocity Strength")
  121. col.prop(fluid, "velocity_radius", text="Radius")
  122. class PHYSICS_PT_fluid_settings(PhysicButtonsPanel, Panel):
  123. bl_label = "Settings"
  124. bl_parent_id = "PHYSICS_PT_fluid"
  125. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
  126. @classmethod
  127. def poll(cls, context):
  128. md = context.fluid
  129. fluid = md.settings
  130. if not PhysicButtonsPanel.poll_fluid_settings(context):
  131. return False
  132. return fluid.type in {'DOMAIN', 'FLUID', 'OBSTACLE', 'PARTICLE'} and (context.engine in cls.COMPAT_ENGINES)
  133. def draw(self, context):
  134. layout = self.layout
  135. layout.use_property_split = True
  136. md = context.fluid
  137. fluid = md.settings
  138. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
  139. if fluid.type not in {'NONE', 'DOMAIN', 'PARTICLE', 'FLUID', 'OBSTACLE'}:
  140. flow.active = fluid.use
  141. if fluid.type == 'DOMAIN':
  142. col = flow.column()
  143. if bpy.app.build_options.openmp:
  144. col.prop(fluid, "threads", text="Simulation Threads")
  145. col.separator()
  146. col.prop(fluid, "resolution", text="Final Resolution")
  147. col.prop(fluid, "preview_resolution", text="Preview")
  148. col.separator()
  149. col = flow.column()
  150. col.prop(fluid, "render_display_mode", text="Render Display")
  151. col.prop(fluid, "viewport_display_mode", text="Viewport")
  152. col.separator()
  153. col = flow.column()
  154. sub = col.column(align=True)
  155. sub.prop(fluid, "start_time", text="Time Start")
  156. sub.prop(fluid, "end_time", text="End")
  157. col.prop(fluid, "simulation_rate", text="Speed")
  158. col = flow.column()
  159. col.prop(fluid, "use_speed_vectors")
  160. col.prop(fluid, "use_reverse_frames")
  161. col.prop(fluid, "frame_offset", text="Offset")
  162. elif fluid.type == 'FLUID':
  163. col = flow.column()
  164. col.prop(fluid, "volume_initialization", text="Volume Initialization")
  165. col.prop(fluid, "use_animated_mesh")
  166. col = flow.column()
  167. col.prop(fluid, "initial_velocity", text="Initial Velocity")
  168. elif fluid.type == 'OBSTACLE':
  169. col = flow.column()
  170. col.prop(fluid, "volume_initialization", text="Volume Initialization")
  171. col.prop(fluid, "use_animated_mesh")
  172. col = flow.column()
  173. subcol = col.column()
  174. subcol.enabled = not fluid.use_animated_mesh
  175. subcol.prop(fluid, "slip_type", text="Slip Type")
  176. if fluid.slip_type == 'PARTIALSLIP':
  177. subcol.prop(fluid, "partial_slip_factor", text="Amount", slider=True)
  178. col.prop(fluid, "impact_factor", text="Impact Factor")
  179. elif fluid.type == 'PARTICLE':
  180. col = flow.column()
  181. col.prop(fluid, "particle_influence", text="Influence Size")
  182. col.prop(fluid, "alpha_influence", text="Alpha")
  183. col = flow.column()
  184. col.prop(fluid, "use_drops")
  185. col.prop(fluid, "use_floats")
  186. col.prop(fluid, "show_tracer")
  187. class PHYSICS_PT_fluid_particle_cache(PhysicButtonsPanel, Panel):
  188. bl_label = "Cache"
  189. bl_parent_id = "PHYSICS_PT_fluid"
  190. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
  191. @classmethod
  192. def poll(cls, context):
  193. if not PhysicButtonsPanel.poll_fluid_settings(context):
  194. return False
  195. md = context.fluid
  196. return md and md.settings and (md.settings.type == 'PARTICLE') and (context.engine in cls.COMPAT_ENGINES)
  197. def draw(self, context):
  198. layout = self.layout
  199. md = context.fluid
  200. fluid = md.settings
  201. layout.prop(fluid, "filepath", text="")
  202. class PHYSICS_PT_domain_bake(PhysicButtonsPanel, Panel):
  203. bl_label = "Bake"
  204. bl_parent_id = 'PHYSICS_PT_fluid'
  205. bl_options = {'DEFAULT_CLOSED'}
  206. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
  207. @classmethod
  208. def poll(cls, context):
  209. if not PhysicButtonsPanel.poll_fluid_domain(context):
  210. return False
  211. return (context.engine in cls.COMPAT_ENGINES)
  212. def draw(self, context):
  213. layout = self.layout
  214. md = context.fluid
  215. fluid = md.settings
  216. row = layout.row(align=True)
  217. row.alignment = 'RIGHT'
  218. row.label(text="Cache Path")
  219. layout.prop(fluid, "filepath", text="")
  220. # odd formatting here so translation script can extract string
  221. layout.operator(
  222. "fluid.bake", text=iface_("Bake (Req. Memory: %s)") % fluid.memory_estimate,
  223. translate=False, icon='MOD_FLUIDSIM'
  224. )
  225. class PHYSICS_PT_domain_gravity(PhysicButtonsPanel, Panel):
  226. bl_label = "World"
  227. bl_parent_id = 'PHYSICS_PT_fluid'
  228. bl_options = {'DEFAULT_CLOSED'}
  229. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
  230. @classmethod
  231. def poll(cls, context):
  232. if not PhysicButtonsPanel.poll_fluid_domain(context):
  233. return False
  234. return (context.engine in cls.COMPAT_ENGINES)
  235. def draw(self, context):
  236. layout = self.layout
  237. layout.use_property_split = True
  238. fluid = context.fluid.settings
  239. scene = context.scene
  240. col = layout.column()
  241. use_gravity = scene.use_gravity
  242. use_units = scene.unit_settings.system != 'NONE'
  243. if use_gravity or use_units:
  244. s_gravity = " Gravity" if use_gravity else ""
  245. s_units = " Units" if use_units else ""
  246. s_and = " and " if use_gravity and use_units else ""
  247. warn = f"Using {s_gravity}{s_and}{s_units} from Scene"
  248. sub = col.column()
  249. sub.alignment = 'RIGHT'
  250. sub.label(text=warn)
  251. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
  252. col = flow.column()
  253. sub = col.column()
  254. sub.enabled = not use_gravity
  255. sub.prop(fluid, "gravity", text="Gravity")
  256. sub = col.column()
  257. sub.enabled = not use_units
  258. sub.prop(fluid, "simulation_scale", text="Scene Size Meters" if use_units else "World Size Meters")
  259. col.separator()
  260. col = flow.column()
  261. col.prop(fluid, "grid_levels", text="Optimization", slider=True)
  262. col.prop(fluid, "compressibility", slider=True)
  263. class PHYSICS_PT_domain_viscosity(PhysicButtonsPanel, Panel):
  264. bl_label = "Viscosity"
  265. bl_parent_id = 'PHYSICS_PT_fluid'
  266. bl_options = {'DEFAULT_CLOSED'}
  267. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
  268. @classmethod
  269. def poll(cls, context):
  270. if not PhysicButtonsPanel.poll_fluid_domain(context):
  271. return False
  272. return (context.engine in cls.COMPAT_ENGINES)
  273. def draw_header_preset(self, _context):
  274. FLUID_PT_presets.draw_panel_header(self.layout)
  275. def draw(self, context):
  276. layout = self.layout
  277. layout.use_property_split = True
  278. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
  279. fluid = context.fluid.settings
  280. col = flow.column()
  281. col.prop(fluid, "viscosity_base", text="Base")
  282. col = flow.column()
  283. col.prop(fluid, "viscosity_exponent", text="Exponent", slider=True)
  284. class PHYSICS_PT_domain_boundary(PhysicButtonsPanel, Panel):
  285. bl_label = "Boundary"
  286. bl_parent_id = 'PHYSICS_PT_fluid'
  287. bl_options = {'DEFAULT_CLOSED'}
  288. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
  289. @classmethod
  290. def poll(cls, context):
  291. if not PhysicButtonsPanel.poll_fluid_domain(context):
  292. return False
  293. return (context.engine in cls.COMPAT_ENGINES)
  294. def draw(self, context):
  295. layout = self.layout
  296. layout.use_property_split = True
  297. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
  298. fluid = context.fluid.settings
  299. col = flow.column()
  300. col.prop(fluid, "slip_type", text="Type")
  301. col.separator()
  302. if fluid.slip_type == 'PARTIALSLIP':
  303. col.prop(fluid, "partial_slip_factor", slider=True, text="Amount")
  304. col = flow.column()
  305. col.prop(fluid, "surface_smooth", text="Surface Smoothing")
  306. col.prop(fluid, "surface_subdivisions", text="Subdivisions")
  307. col.prop(fluid, "use_surface_noobs")
  308. class PHYSICS_PT_domain_particles(PhysicButtonsPanel, Panel):
  309. bl_label = "Particles"
  310. bl_parent_id = 'PHYSICS_PT_fluid'
  311. bl_options = {'DEFAULT_CLOSED'}
  312. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
  313. @classmethod
  314. def poll(cls, context):
  315. if not PhysicButtonsPanel.poll_fluid_domain(context):
  316. return False
  317. return (context.engine in cls.COMPAT_ENGINES)
  318. def draw(self, context):
  319. layout = self.layout
  320. layout.use_property_split = True
  321. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
  322. fluid = context.fluid.settings
  323. col = flow.column()
  324. col.prop(fluid, "tracer_particles", text="Tracer")
  325. col = flow.column()
  326. col.prop(fluid, "generate_particles", text="Generate")
  327. classes = (
  328. FLUID_PT_presets,
  329. PHYSICS_PT_fluid,
  330. PHYSICS_PT_fluid_settings,
  331. PHYSICS_PT_fluid_flow,
  332. PHYSICS_PT_fluid_particle_cache,
  333. PHYSICS_PT_domain_bake,
  334. PHYSICS_PT_domain_boundary,
  335. PHYSICS_PT_domain_particles,
  336. PHYSICS_PT_domain_gravity,
  337. PHYSICS_PT_domain_viscosity,
  338. )
  339. if __name__ == "__main__": # only for live edit.
  340. from bpy.utils import register_class
  341. for cls in classes:
  342. register_class(cls)