properties_physics_field.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  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. from bpy.types import (
  20. Panel,
  21. )
  22. from bl_ui.properties_physics_common import (
  23. basic_force_field_settings_ui,
  24. basic_force_field_falloff_ui,
  25. )
  26. class PhysicButtonsPanel:
  27. bl_space_type = 'PROPERTIES'
  28. bl_region_type = 'WINDOW'
  29. bl_context = "physics"
  30. @staticmethod
  31. def poll_force_field(context):
  32. ob = context.object
  33. return (ob and (ob.field) and (ob.field.type != 'NONE'))
  34. @staticmethod
  35. def poll_collision(context):
  36. ob = context.object
  37. return (ob and ob.type == 'MESH') and (context.collision)
  38. class PHYSICS_PT_field(PhysicButtonsPanel, Panel):
  39. bl_label = "Force Fields"
  40. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
  41. @classmethod
  42. def poll(cls, context):
  43. if not PhysicButtonsPanel.poll_force_field(context):
  44. return False
  45. return (context.engine in cls.COMPAT_ENGINES)
  46. def draw(self, context):
  47. layout = self.layout
  48. layout.use_property_split = True
  49. ob = context.object
  50. field = ob.field
  51. layout.prop(field, "type")
  52. class PHYSICS_PT_field_settings(PhysicButtonsPanel, Panel):
  53. bl_label = "Settings"
  54. bl_parent_id = 'PHYSICS_PT_field'
  55. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
  56. @classmethod
  57. def poll(cls, context):
  58. if not PhysicButtonsPanel.poll_force_field(context):
  59. return False
  60. return (context.engine in cls.COMPAT_ENGINES)
  61. def draw(self, context):
  62. layout = self.layout
  63. layout.use_property_split = True
  64. ob = context.object
  65. field = ob.field
  66. if field.type not in {'NONE', 'GUIDE', 'TEXTURE'}:
  67. layout.prop(field, "shape", text="Shape")
  68. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
  69. if field.type == 'NONE':
  70. return # nothing to draw.
  71. elif field.type == 'GUIDE':
  72. col = flow.column()
  73. col.prop(field, "guide_minimum")
  74. col.prop(field, "guide_free")
  75. col.prop(field, "falloff_power")
  76. col.prop(field, "use_guide_path_add")
  77. col.prop(field, "use_guide_path_weight")
  78. col.separator()
  79. col = flow.column()
  80. col.prop(field, "guide_clump_amount", text="Clumping amount")
  81. col.prop(field, "guide_clump_shape")
  82. col.prop(field, "use_max_distance")
  83. sub = col.column()
  84. sub.active = field.use_max_distance
  85. sub.prop(field, "distance_max")
  86. elif field.type == 'TEXTURE':
  87. col = flow.column()
  88. col.prop(field, "texture_mode")
  89. col.separator()
  90. col.prop(field, "strength")
  91. col = flow.column()
  92. col.prop(field, "texture_nabla")
  93. col.prop(field, "use_object_coords")
  94. col.prop(field, "use_2d_force")
  95. elif field.type == 'SMOKE_FLOW':
  96. col = flow.column()
  97. col.prop(field, "strength")
  98. col.prop(field, "flow")
  99. col = flow.column()
  100. col.prop(field, "source_object")
  101. col.prop(field, "use_smoke_density")
  102. else:
  103. del flow
  104. basic_force_field_settings_ui(self, field)
  105. class PHYSICS_PT_field_settings_kink(PhysicButtonsPanel, Panel):
  106. bl_label = "Kink"
  107. bl_parent_id = 'PHYSICS_PT_field_settings'
  108. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
  109. @classmethod
  110. def poll(cls, context):
  111. if not PhysicButtonsPanel.poll_force_field(context):
  112. return False
  113. ob = context.object
  114. return ((ob.field.type == 'GUIDE') and (context.engine in cls.COMPAT_ENGINES))
  115. def draw(self, context):
  116. layout = self.layout
  117. layout.use_property_split = True
  118. ob = context.object
  119. field = ob.field
  120. layout.prop(field, "guide_kink_type", text="Type")
  121. if field.guide_kink_type != 'NONE':
  122. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
  123. col = flow.column()
  124. col.prop(field, "guide_kink_axis")
  125. col.prop(field, "guide_kink_frequency")
  126. col = flow.column()
  127. col.prop(field, "guide_kink_shape")
  128. col.prop(field, "guide_kink_amplitude")
  129. class PHYSICS_PT_field_settings_texture_select(PhysicButtonsPanel, Panel):
  130. bl_label = "Texture"
  131. bl_parent_id = 'PHYSICS_PT_field_settings'
  132. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
  133. @classmethod
  134. def poll(cls, context):
  135. if not PhysicButtonsPanel.poll_force_field(context):
  136. return False
  137. ob = context.object
  138. return ((ob.field.type == 'TEXTURE') and (context.engine in cls.COMPAT_ENGINES))
  139. def draw(self, context):
  140. layout = self.layout
  141. ob = context.object
  142. field = ob.field
  143. layout.row().template_ID(field, "texture", new="texture.new")
  144. class PHYSICS_PT_field_falloff(PhysicButtonsPanel, Panel):
  145. bl_label = "Falloff"
  146. bl_parent_id = "PHYSICS_PT_field"
  147. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
  148. @classmethod
  149. def poll(cls, context):
  150. if not PhysicButtonsPanel.poll_force_field(context):
  151. return False
  152. ob = context.object
  153. return ((ob.field.type not in {'NONE', 'GUIDE'}) and (context.engine in cls.COMPAT_ENGINES))
  154. def draw(self, context):
  155. layout = self.layout
  156. layout.use_property_split = True
  157. ob = context.object
  158. field = ob.field
  159. layout.prop(field, "falloff_type", text="Shape")
  160. basic_force_field_falloff_ui(self, field)
  161. class PHYSICS_PT_field_falloff_angular(PhysicButtonsPanel, Panel):
  162. bl_label = "Angular"
  163. bl_parent_id = "PHYSICS_PT_field_falloff"
  164. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
  165. @classmethod
  166. def poll(cls, context):
  167. if not PhysicButtonsPanel.poll_force_field(context):
  168. return False
  169. ob = context.object
  170. return ((ob.field.falloff_type == 'CONE') and (context.engine in cls.COMPAT_ENGINES))
  171. def draw(self, context):
  172. layout = self.layout
  173. layout.use_property_split = True
  174. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
  175. ob = context.object
  176. field = ob.field
  177. col = flow.column()
  178. col.prop(field, "radial_falloff", text="Power")
  179. col = flow.column()
  180. col.prop(field, "use_radial_min", text="Use Min Angle")
  181. sub = col.column()
  182. sub.active = field.use_radial_min
  183. sub.prop(field, "radial_min", text="Min Angle")
  184. col = flow.column()
  185. col.prop(field, "use_radial_max", text="Use Max Angle")
  186. sub = col.column()
  187. sub.active = field.use_radial_max
  188. sub.prop(field, "radial_max", text="Max Angle")
  189. class PHYSICS_PT_field_falloff_radial(PhysicButtonsPanel, Panel):
  190. bl_label = "Radial"
  191. bl_parent_id = "PHYSICS_PT_field_falloff"
  192. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
  193. @classmethod
  194. def poll(cls, context):
  195. if not PhysicButtonsPanel.poll_force_field(context):
  196. return False
  197. ob = context.object
  198. return ((ob.field.falloff_type == 'TUBE') and (context.engine in cls.COMPAT_ENGINES))
  199. def draw(self, context):
  200. layout = self.layout
  201. layout.use_property_split = True
  202. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
  203. ob = context.object
  204. field = ob.field
  205. col = flow.column()
  206. col.prop(field, "radial_falloff", text="Power")
  207. col = flow.column()
  208. col.prop(field, "use_radial_min", text="Use Minimum")
  209. sub = col.column()
  210. sub.active = field.use_radial_min
  211. sub.prop(field, "radial_min", text="Min Distance")
  212. col = flow.column()
  213. col.prop(field, "use_radial_max", text="Use Maximum")
  214. sub = col.column()
  215. sub.active = field.use_radial_max
  216. sub.prop(field, "radial_max", text="Max Distance")
  217. def collision_warning(layout):
  218. row = layout.row(align=True)
  219. row.alignment = 'RIGHT'
  220. row.label(text="No collision settings available")
  221. class PHYSICS_PT_collision(PhysicButtonsPanel, Panel):
  222. bl_label = "Collision"
  223. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
  224. @classmethod
  225. def poll(cls, context):
  226. if not PhysicButtonsPanel.poll_collision(context):
  227. return False
  228. return (context.engine in cls.COMPAT_ENGINES)
  229. def draw(self, context):
  230. layout = self.layout
  231. layout.use_property_split = True
  232. md = context.collision
  233. coll = md.settings
  234. if not coll:
  235. collision_warning(layout)
  236. return
  237. settings = context.object.collision
  238. layout.active = settings.use
  239. col = layout.column()
  240. col.prop(settings, "absorption", text="Field Absorption")
  241. class PHYSICS_PT_collision_particle(PhysicButtonsPanel, Panel):
  242. bl_label = "Particle"
  243. bl_parent_id = "PHYSICS_PT_collision"
  244. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
  245. @classmethod
  246. def poll(cls, context):
  247. if not PhysicButtonsPanel.poll_collision(context):
  248. return False
  249. return (context.engine in cls.COMPAT_ENGINES)
  250. def draw(self, context):
  251. layout = self.layout
  252. md = context.collision
  253. layout.use_property_split = True
  254. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
  255. coll = md.settings
  256. if not coll:
  257. collision_warning(layout)
  258. return
  259. settings = context.object.collision
  260. layout.active = settings.use
  261. col = flow.column()
  262. col.prop(settings, "permeability", slider=True)
  263. col.prop(settings, "stickiness")
  264. col.prop(settings, "use_particle_kill")
  265. col = flow.column()
  266. sub = col.column(align=True)
  267. sub.prop(settings, "damping_factor", text="Damping", slider=True)
  268. sub.prop(settings, "damping_random", text="Randomize", slider=True)
  269. col = flow.column()
  270. sub = col.column(align=True)
  271. sub.prop(settings, "friction_factor", text="Friction", slider=True)
  272. sub.prop(settings, "friction_random", text="Randomize", slider=True)
  273. class PHYSICS_PT_collision_softbody(PhysicButtonsPanel, Panel):
  274. bl_label = "Softbody And Cloth"
  275. bl_parent_id = "PHYSICS_PT_collision"
  276. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
  277. @classmethod
  278. def poll(cls, context):
  279. if not PhysicButtonsPanel.poll_collision(context):
  280. return False
  281. return (context.engine in cls.COMPAT_ENGINES)
  282. def draw(self, context):
  283. layout = self.layout
  284. layout.use_property_split = True
  285. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
  286. md = context.collision
  287. coll = md.settings
  288. if not coll:
  289. collision_warning(layout)
  290. return
  291. settings = context.object.collision
  292. layout.active = settings.use
  293. col = flow.column()
  294. col.prop(settings, "damping", text="Damping", slider=True)
  295. col = flow.column()
  296. col.prop(settings, "thickness_outer", text="Thickness Outer", slider=True)
  297. col = flow.column()
  298. col.prop(settings, "thickness_inner", text="Inner", slider=True)
  299. col = flow.column()
  300. col.prop(settings, "cloth_friction")
  301. col = flow.column()
  302. col.prop(settings, "use_culling")
  303. col = flow.column()
  304. col.prop(settings, "use_normal")
  305. classes = (
  306. PHYSICS_PT_field,
  307. PHYSICS_PT_field_settings,
  308. PHYSICS_PT_field_settings_kink,
  309. PHYSICS_PT_field_settings_texture_select,
  310. PHYSICS_PT_field_falloff,
  311. PHYSICS_PT_field_falloff_angular,
  312. PHYSICS_PT_field_falloff_radial,
  313. PHYSICS_PT_collision,
  314. PHYSICS_PT_collision_particle,
  315. PHYSICS_PT_collision_softbody,
  316. )
  317. if __name__ == "__main__": # only for live edit.
  318. from bpy.utils import register_class
  319. for cls in classes:
  320. register_class(cls)