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 19# <pep8 compliant> 20 21from bpy.types import ( 22 Panel, 23 UIList, 24) 25from bl_ui.properties_physics_common import ( 26 point_cache_ui, 27 effector_weights_ui, 28) 29 30 31class PHYSICS_UL_dynapaint_surfaces(UIList): 32 def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index): 33 # assert(isinstance(item, bpy.types.DynamicPaintSurface) 34 surf = item 35 sticon = layout.enum_item_icon(surf, "surface_type", surf.surface_type) 36 37 if self.layout_type in {'DEFAULT', 'COMPACT'}: 38 row = layout.row(align=True) 39 row.label(text="", icon_value=icon) 40 row.prop(surf, "name", text="", emboss=False, icon_value=sticon) 41 row = layout.row(align=True) 42 row.prop(surf, "is_active", text="") 43 44 elif self.layout_type == 'GRID': 45 layout.alignment = 'CENTER' 46 row = layout.row(align=True) 47 row.label(text="", icon_value=icon) 48 row.label(text="", icon_value=sticon) 49 50 51class PhysicButtonsPanel: 52 bl_space_type = 'PROPERTIES' 53 bl_region_type = 'WINDOW' 54 bl_context = "physics" 55 56 @staticmethod 57 def poll_dyn_paint(context): 58 ob = context.object 59 return (ob and ob.type == 'MESH') and context.dynamic_paint 60 61 @staticmethod 62 def poll_dyn_canvas(context): 63 if not PhysicButtonsPanel.poll_dyn_paint(context): 64 return False 65 66 md = context.dynamic_paint 67 return (md and md.ui_type == 'CANVAS' and md.canvas_settings and md.canvas_settings.canvas_surfaces.active) 68 69 @staticmethod 70 def poll_dyn_canvas_paint(context): 71 if not PhysicButtonsPanel.poll_dyn_canvas(context): 72 return False 73 74 surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active 75 return (surface.surface_type == 'PAINT') 76 77 @staticmethod 78 def poll_dyn_canvas_brush(context): 79 if not PhysicButtonsPanel.poll_dyn_paint(context): 80 return False 81 82 md = context.dynamic_paint 83 return (md and md.ui_type == 'BRUSH' and md.brush_settings) 84 85 @staticmethod 86 def poll_dyn_output(context): 87 if not PhysicButtonsPanel.poll_dyn_canvas(context): 88 return False 89 90 surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active 91 return (not (surface.surface_format == 'VERTEX' and (surface.surface_type in {'DISPLACE', 'WAVE'}))) 92 93 @staticmethod 94 def poll_dyn_output_maps(context): 95 if not PhysicButtonsPanel.poll_dyn_output(context): 96 return False 97 98 surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active 99 return (surface.surface_format == 'IMAGE' and surface.surface_type == 'PAINT') 100 101 102class PHYSICS_PT_dynamic_paint(PhysicButtonsPanel, Panel): 103 bl_label = "Dynamic Paint" 104 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 105 106 @classmethod 107 def poll(cls, context): 108 if not PhysicButtonsPanel.poll_dyn_paint(context): 109 return False 110 111 return (context.engine in cls.COMPAT_ENGINES) 112 113 def draw(self, context): 114 layout = self.layout 115 layout.use_property_split = True 116 117 md = context.dynamic_paint 118 119 layout.prop(md, "ui_type") 120 121 122class PHYSICS_PT_dynamic_paint_settings(PhysicButtonsPanel, Panel): 123 bl_label = "Settings" 124 bl_parent_id = 'PHYSICS_PT_dynamic_paint' 125 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 126 127 @classmethod 128 def poll(cls, context): 129 if not PhysicButtonsPanel.poll_dyn_paint(context): 130 return False 131 132 return (context.engine in cls.COMPAT_ENGINES) 133 134 def draw(self, context): 135 layout = self.layout 136 137 md = context.dynamic_paint 138 139 if md.ui_type == 'CANVAS': 140 canvas = md.canvas_settings 141 142 if canvas is None: 143 layout.operator("dpaint.type_toggle", text="Add Canvas").type = 'CANVAS' 144 return # do nothing. 145 146 layout.operator("dpaint.type_toggle", text="Remove Canvas", icon='X').type = 'CANVAS' 147 148 surface = canvas.canvas_surfaces.active 149 150 row = layout.row() 151 row.template_list( 152 "PHYSICS_UL_dynapaint_surfaces", "", canvas, "canvas_surfaces", 153 canvas.canvas_surfaces, "active_index", rows=1, 154 ) 155 156 col = row.column(align=True) 157 col.operator("dpaint.surface_slot_add", icon='ADD', text="") 158 col.operator("dpaint.surface_slot_remove", icon='REMOVE', text="") 159 160 layout.separator() 161 162 layout.use_property_split = True 163 164 if surface: 165 flow = layout.grid_flow( 166 row_major=True, columns=0, even_columns=True, even_rows=False, align=False, 167 ) 168 col = flow.column() 169 170 col.prop(surface, "surface_format") 171 172 if surface.surface_format != 'VERTEX': 173 col.prop(surface, "image_resolution") 174 col.prop(surface, "use_antialiasing") 175 176 col = flow.column(align=True) 177 col.prop(surface, "frame_start", text="Frame Start") 178 col.prop(surface, "frame_end", text="End") 179 180 col.prop(surface, "frame_substeps") 181 182 elif md.ui_type == 'BRUSH': 183 brush = md.brush_settings 184 185 if brush is None: 186 layout.operator("dpaint.type_toggle", text="Add Brush").type = 'BRUSH' 187 return # do nothing. 188 189 layout.operator("dpaint.type_toggle", text="Remove Brush", icon='X').type = 'BRUSH' 190 191 layout.use_property_split = True 192 193 flow = layout.grid_flow( 194 row_major=True, columns=0, even_columns=True, even_rows=False, align=False, 195 ) 196 col = flow.column() 197 col.prop(brush, "paint_color") 198 col.prop(brush, "paint_alpha", text="Alpha", slider=True) 199 200 col = flow.column() 201 col.prop(brush, "paint_wetness", text="Wetness", slider=True) 202 col.prop(brush, "use_absolute_alpha") 203 col.prop(brush, "use_paint_erase") 204 205 206class PHYSICS_PT_dp_surface_canvas(PhysicButtonsPanel, Panel): 207 bl_label = "Surface" 208 bl_parent_id = "PHYSICS_PT_dynamic_paint" 209 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 210 211 @classmethod 212 def poll(cls, context): 213 if not PhysicButtonsPanel.poll_dyn_canvas(context): 214 return False 215 216 return (context.engine in cls.COMPAT_ENGINES) 217 218 def draw(self, context): 219 layout = self.layout 220 layout.use_property_split = True 221 222 canvas = context.dynamic_paint.canvas_settings 223 surface = canvas.canvas_surfaces.active 224 surface_type = surface.surface_type 225 226 layout.prop(surface, "surface_type") 227 228 layout.separator() 229 230 flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) 231 232 # per type settings 233 if surface_type == 'DISPLACE': 234 col = flow.column() 235 236 if surface.surface_format == 'VERTEX': 237 col.prop(surface, "depth_clamp") 238 col.prop(surface, "displace_factor") 239 240 col.prop(surface, "use_incremental_displace") 241 col.separator() 242 243 elif surface_type == 'WAVE': 244 col = flow.column() 245 col.prop(surface, "use_wave_open_border") 246 col.prop(surface, "wave_timescale") 247 col.prop(surface, "wave_speed") 248 249 col.separator() 250 251 col = flow.column() 252 col.prop(surface, "wave_damping") 253 col.prop(surface, "wave_spring") 254 col.prop(surface, "wave_smoothness") 255 256 col.separator() 257 258 col = flow.column() 259 col.prop(surface, "brush_collection") 260 261 if surface_type not in {'DISPLACE', 'WAVE'}: 262 col = flow.column() # flow the layout otherwise. 263 264 col.prop(surface, "brush_influence_scale", text="Scale Influence") 265 col.prop(surface, "brush_radius_scale", text="Radius") 266 267 268class PHYSICS_PT_dp_surface_canvas_paint_dry(PhysicButtonsPanel, Panel): 269 bl_label = "Dry" 270 bl_parent_id = "PHYSICS_PT_dp_surface_canvas" 271 bl_options = {'DEFAULT_CLOSED'} 272 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 273 274 @classmethod 275 def poll(cls, context): 276 if not PhysicButtonsPanel.poll_dyn_canvas_paint(context): 277 return False 278 279 return (context.engine in cls.COMPAT_ENGINES) 280 281 def draw_header(self, context): 282 canvas = context.dynamic_paint.canvas_settings 283 surface = canvas.canvas_surfaces.active 284 self.layout.prop(surface, "use_drying", text="") 285 286 def draw(self, context): 287 layout = self.layout 288 layout.use_property_split = True 289 flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) 290 291 canvas = context.dynamic_paint.canvas_settings 292 surface = canvas.canvas_surfaces.active 293 294 flow.active = surface.use_drying 295 296 col = flow.column() 297 col.prop(surface, "dry_speed", text="Time") 298 299 col = flow.column() 300 col.prop(surface, "color_dry_threshold", text="Color") 301 col.prop(surface, "use_dry_log", text="Slow") 302 303 304class PHYSICS_PT_dp_surface_canvas_paint_dissolve(PhysicButtonsPanel, Panel): 305 bl_label = "Dissolve" 306 bl_parent_id = "PHYSICS_PT_dp_surface_canvas" 307 bl_options = {'DEFAULT_CLOSED'} 308 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 309 310 @classmethod 311 def poll(cls, context): 312 if not PhysicButtonsPanel.poll_dyn_canvas(context): 313 return False 314 315 surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active 316 317 return (surface.surface_type != 'WAVE' and context.engine in cls.COMPAT_ENGINES) 318 319 def draw_header(self, context): 320 canvas = context.dynamic_paint.canvas_settings 321 surface = canvas.canvas_surfaces.active 322 self.layout.prop(surface, "use_dissolve", text="") 323 324 def draw(self, context): 325 layout = self.layout 326 layout.use_property_split = True 327 flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) 328 329 canvas = context.dynamic_paint.canvas_settings 330 surface = canvas.canvas_surfaces.active 331 332 flow.active = surface.use_dissolve 333 334 col = flow.column() 335 col.prop(surface, "dissolve_speed", text="Time") 336 337 col = flow.column() 338 col.prop(surface, "use_dissolve_log", text="Slow") 339 340 341class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel): 342 bl_label = "Output" 343 bl_parent_id = "PHYSICS_PT_dynamic_paint" 344 bl_options = {'DEFAULT_CLOSED'} 345 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 346 347 @classmethod 348 def poll(cls, context): 349 if not PhysicButtonsPanel.poll_dyn_output(context): 350 return False 351 352 return (context.engine in cls.COMPAT_ENGINES) 353 354 def draw(self, context): 355 layout = self.layout 356 layout.use_property_split = True 357 358 canvas = context.dynamic_paint.canvas_settings 359 surface = canvas.canvas_surfaces.active 360 ob = context.object 361 362 surface_type = surface.surface_type 363 364 # vertex format outputs. 365 if surface.surface_format == 'VERTEX': 366 if surface_type == 'PAINT': 367 # paint-map output. 368 row = layout.row() 369 row.prop_search(surface, "output_name_a", ob.data, "vertex_colors", text="Paintmap Layer") 370 371 icons = 'REMOVE' if surface.output_exists(object=ob, index=0) else 'ADD' 372 row.operator("dpaint.output_toggle", icon=icons, text="").output = 'A' 373 374 # wet-map output. 375 row = layout.row() 376 row.prop_search(surface, "output_name_b", ob.data, "vertex_colors", text="Wetmap Layer") 377 378 icons = 'REMOVE' if surface.output_exists(object=ob, index=1) else 'ADD' 379 row.operator("dpaint.output_toggle", icon=icons, text="").output = 'B' 380 381 elif surface_type == 'WEIGHT': 382 row = layout.row() 383 row.prop_search(surface, "output_name_a", ob, "vertex_groups", text="Vertex Group") 384 385 icons = 'REMOVE' if surface.output_exists(object=ob, index=0) else 'ADD' 386 row.operator("dpaint.output_toggle", icon=icons, text="").output = 'A' 387 388 # image format outputs. 389 if surface.surface_format == 'IMAGE': 390 391 layout.operator("dpaint.bake", text="Bake Image Sequence", icon='MOD_DYNAMICPAINT') 392 393 layout.prop(surface, "image_output_path", text="Cache Path") 394 395 flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) 396 397 col = flow.column() 398 399 col.prop_search(surface, "uv_layer", ob.data, "uv_layers", text="UV Map") 400 401 col = flow.column() 402 col.prop(surface, "image_fileformat") 403 col.prop(surface, "use_premultiply", text="Premultiply Alpha") 404 405 if surface_type != 'PAINT': 406 col = col.column() 407 col.prop(surface, "output_name_a", text="Filename") 408 409 if surface_type == 'DISPLACE': 410 col.prop(surface, "displace_type", text="Displace Type") 411 col.prop(surface, "depth_clamp") 412 413 elif surface_type == 'WAVE': 414 col.prop(surface, "depth_clamp", text="Wave Clamp") 415 416 417class PHYSICS_PT_dp_canvas_output_paintmaps(PhysicButtonsPanel, Panel): 418 bl_label = "Paintmaps" 419 bl_parent_id = "PHYSICS_PT_dp_canvas_output" 420 bl_options = {'DEFAULT_CLOSED'} 421 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 422 423 @classmethod 424 def poll(cls, context): 425 if not PhysicButtonsPanel.poll_dyn_output_maps(context): 426 return False 427 428 return (context.engine in cls.COMPAT_ENGINES) 429 430 def draw_header(self, context): 431 canvas = context.dynamic_paint.canvas_settings 432 surface = canvas.canvas_surfaces.active 433 self.layout.prop(surface, "use_output_a", text="") 434 435 def draw(self, context): 436 layout = self.layout 437 layout.use_property_split = True 438 439 canvas = context.dynamic_paint.canvas_settings 440 surface = canvas.canvas_surfaces.active 441 442 sub = layout.column() 443 sub.active = surface.use_output_a 444 sub.prop(surface, "output_name_a", text="Name") 445 446 447class PHYSICS_PT_dp_canvas_output_wetmaps(PhysicButtonsPanel, Panel): 448 bl_label = "Wetmaps" 449 bl_parent_id = "PHYSICS_PT_dp_canvas_output" 450 bl_options = {'DEFAULT_CLOSED'} 451 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 452 453 @classmethod 454 def poll(cls, context): 455 if not PhysicButtonsPanel.poll_dyn_output_maps(context): 456 return False 457 458 return (context.engine in cls.COMPAT_ENGINES) 459 460 def draw_header(self, context): 461 canvas = context.dynamic_paint.canvas_settings 462 surface = canvas.canvas_surfaces.active 463 self.layout.prop(surface, "use_output_b", text="") 464 465 def draw(self, context): 466 layout = self.layout 467 layout.use_property_split = True 468 469 canvas = context.dynamic_paint.canvas_settings 470 surface = canvas.canvas_surfaces.active 471 472 sub = layout.column() 473 sub.active = surface.use_output_b 474 sub.prop(surface, "output_name_b", text="Name") 475 476 477class PHYSICS_PT_dp_canvas_initial_color(PhysicButtonsPanel, Panel): 478 bl_label = "Initial Color" 479 bl_parent_id = "PHYSICS_PT_dynamic_paint" 480 bl_options = {'DEFAULT_CLOSED'} 481 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 482 483 @classmethod 484 def poll(cls, context): 485 if not PhysicButtonsPanel.poll_dyn_canvas_paint(context): 486 return False 487 488 return (context.engine in cls.COMPAT_ENGINES) 489 490 def draw(self, context): 491 layout = self.layout 492 493 canvas = context.dynamic_paint.canvas_settings 494 surface = canvas.canvas_surfaces.active 495 ob = context.object 496 497 layout.use_property_split = True 498 499 col = layout.column() 500 col.prop(surface, "init_color_type", text="Type", expand=False) 501 502 if surface.init_color_type != 'NONE': 503 col.separator() 504 505 # dissolve 506 if surface.init_color_type == 'COLOR': 507 layout.prop(surface, "init_color") 508 509 elif surface.init_color_type == 'TEXTURE': 510 col.prop(surface, "init_texture") 511 col.prop_search(surface, "init_layername", ob.data, "uv_layers", text="UV Map") 512 513 elif surface.init_color_type == 'VERTEX_COLOR': 514 col.prop_search(surface, "init_layername", ob.data, "vertex_colors", text="Color Layer") 515 516 517class PHYSICS_PT_dp_effects(PhysicButtonsPanel, Panel): 518 bl_label = "Effects" 519 bl_parent_id = 'PHYSICS_PT_dynamic_paint' 520 bl_options = {'DEFAULT_CLOSED'} 521 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 522 523 @classmethod 524 def poll(cls, context): 525 if not PhysicButtonsPanel.poll_dyn_canvas_paint(context): 526 return False 527 528 return (context.engine in cls.COMPAT_ENGINES) 529 530 def draw(self, _context): 531 return # do nothing. 532 533 534class PHYSICS_PT_dp_effects_spread(PhysicButtonsPanel, Panel): 535 bl_label = "Spread" 536 bl_parent_id = "PHYSICS_PT_dp_effects" 537 bl_options = {'DEFAULT_CLOSED'} 538 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 539 540 @classmethod 541 def poll(cls, context): 542 if not PhysicButtonsPanel.poll_dyn_paint(context): 543 return False 544 545 return (context.engine in cls.COMPAT_ENGINES) 546 547 def draw_header(self, context): 548 canvas = context.dynamic_paint.canvas_settings 549 surface = canvas.canvas_surfaces.active 550 551 self.layout.prop(surface, "use_spread", text="") 552 553 def draw(self, context): 554 layout = self.layout 555 layout.use_property_split = True 556 flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) 557 558 canvas = context.dynamic_paint.canvas_settings 559 surface = canvas.canvas_surfaces.active 560 layout.active = surface.use_spread 561 562 col = flow.column() 563 col.prop(surface, "spread_speed", text="Speed") 564 565 col = flow.column() 566 col.prop(surface, "color_spread_speed", text="Color") 567 568 569class PHYSICS_PT_dp_effects_drip(PhysicButtonsPanel, Panel): 570 bl_label = "Drip" 571 bl_parent_id = "PHYSICS_PT_dp_effects" 572 bl_options = {'DEFAULT_CLOSED'} 573 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 574 575 @classmethod 576 def poll(cls, context): 577 if not PhysicButtonsPanel.poll_dyn_paint(context): 578 return False 579 580 return (context.engine in cls.COMPAT_ENGINES) 581 582 def draw_header(self, context): 583 canvas = context.dynamic_paint.canvas_settings 584 surface = canvas.canvas_surfaces.active 585 586 self.layout.prop(surface, "use_drip", text="") 587 588 def draw(self, context): 589 layout = self.layout 590 layout.use_property_split = True 591 flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) 592 593 canvas = context.dynamic_paint.canvas_settings 594 surface = canvas.canvas_surfaces.active 595 596 flow.active = surface.use_drip 597 598 col = flow.column() 599 col.prop(surface, "drip_velocity", slider=True) 600 601 col = flow.column() 602 col.prop(surface, "drip_acceleration", slider=True) 603 604 605class PHYSICS_PT_dp_effects_drip_weights(PhysicButtonsPanel, Panel): 606 bl_label = "Weights" 607 bl_parent_id = "PHYSICS_PT_dp_effects_drip" 608 bl_options = {'DEFAULT_CLOSED'} 609 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 610 611 @classmethod 612 def poll(cls, context): 613 if not PhysicButtonsPanel.poll_dyn_paint(context): 614 return False 615 616 return (context.engine in cls.COMPAT_ENGINES) 617 618 def draw(self, context): 619 layout = self.layout 620 621 canvas = context.dynamic_paint.canvas_settings 622 surface = canvas.canvas_surfaces.active 623 624 layout.active = surface.use_drip 625 626 effector_weights_ui(self, surface.effector_weights, 'DYNAMIC_PAINT') 627 628 629class PHYSICS_PT_dp_effects_shrink(PhysicButtonsPanel, Panel): 630 bl_label = "Shrink" 631 bl_parent_id = "PHYSICS_PT_dp_effects" 632 bl_options = {'DEFAULT_CLOSED'} 633 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 634 635 @classmethod 636 def poll(cls, context): 637 if not PhysicButtonsPanel.poll_dyn_paint(context): 638 return False 639 640 return (context.engine in cls.COMPAT_ENGINES) 641 642 def draw_header(self, context): 643 canvas = context.dynamic_paint.canvas_settings 644 surface = canvas.canvas_surfaces.active 645 646 self.layout.prop(surface, "use_shrink", text="") 647 648 def draw(self, context): 649 layout = self.layout 650 layout.use_property_split = True 651 652 canvas = context.dynamic_paint.canvas_settings 653 surface = canvas.canvas_surfaces.active 654 layout.active = surface.use_shrink 655 656 layout.prop(surface, "shrink_speed", text="Speed") 657 658 659class PHYSICS_PT_dp_cache(PhysicButtonsPanel, Panel): 660 bl_label = "Cache" 661 bl_parent_id = "PHYSICS_PT_dynamic_paint" 662 bl_options = {'DEFAULT_CLOSED'} 663 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 664 665 @classmethod 666 def poll(cls, context): 667 if not PhysicButtonsPanel.poll_dyn_canvas(context): 668 return False 669 670 surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active 671 return (surface.is_cache_user and (context.engine in cls.COMPAT_ENGINES)) 672 673 def draw(self, context): 674 surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active 675 cache = surface.point_cache 676 677 point_cache_ui(self, cache, (cache.is_baked is False), 'DYNAMIC_PAINT') 678 679 680class PHYSICS_PT_dp_brush_source(PhysicButtonsPanel, Panel): 681 bl_label = "Source" 682 bl_parent_id = "PHYSICS_PT_dynamic_paint" 683 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 684 685 @classmethod 686 def poll(cls, context): 687 if not PhysicButtonsPanel.poll_dyn_canvas_brush(context): 688 return False 689 690 return (context.engine in cls.COMPAT_ENGINES) 691 692 def draw(self, context): 693 layout = self.layout 694 layout.use_property_split = True 695 696 brush = context.dynamic_paint.brush_settings 697 ob = context.object 698 699 layout.prop(brush, "paint_source", text="Paint") 700 701 flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) 702 703 if brush.paint_source == 'PARTICLE_SYSTEM': 704 col = flow.column() 705 706 col.separator() 707 708 col.prop_search(brush, "particle_system", ob, "particle_systems") 709 710 if brush.particle_system: 711 col = flow.column() 712 713 sub = col.column() 714 sub.active = not brush.use_particle_radius 715 sub.prop(brush, "solid_radius", text="Effect Solid Radius") 716 717 col.prop(brush, "use_particle_radius", text="Use Particle's Radius") 718 col.prop(brush, "smooth_radius", text="Smooth Radius") 719 720 if brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE', 'POINT'}: 721 col = flow.column() 722 723 col.separator() 724 725 col.prop(brush, "paint_distance", text="Distance") 726 col.prop(brush, "proximity_falloff") 727 728 if brush.paint_source == 'VOLUME_DISTANCE': 729 col.prop(brush, "invert_proximity") 730 731 col = flow.column() 732 col.prop(brush, "use_negative_volume") 733 734 if brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE'}: 735 col = flow.column() if brush.paint_source != 'VOLUME_DISTANCE' else col.column() 736 col.prop(brush, "use_proximity_project") 737 738 sub = col.column() 739 sub.active = brush.use_proximity_project 740 sub.prop(brush, "ray_direction") 741 742 743class PHYSICS_PT_dp_brush_source_color_ramp(PhysicButtonsPanel, Panel): 744 bl_label = "Falloff Ramp" 745 bl_parent_id = "PHYSICS_PT_dp_brush_source" 746 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 747 748 @classmethod 749 def poll(cls, context): 750 if not PhysicButtonsPanel.poll_dyn_canvas_brush(context): 751 return False 752 753 brush = context.dynamic_paint.brush_settings 754 return ((brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE', 'POINT'}) 755 and (brush.proximity_falloff == 'RAMP') 756 and (context.engine in cls.COMPAT_ENGINES)) 757 758 def draw(self, context): 759 layout = self.layout 760 layout.use_property_split = True 761 762 brush = context.dynamic_paint.brush_settings 763 layout.prop(brush, "use_proximity_ramp_alpha", text="Only Use Alpha") 764 765 layout.use_property_split = False 766 layout.template_color_ramp(brush, "paint_ramp", expand=True) 767 768 769class PHYSICS_PT_dp_brush_velocity(PhysicButtonsPanel, Panel): 770 bl_label = "Velocity" 771 bl_parent_id = "PHYSICS_PT_dynamic_paint" 772 bl_options = {'DEFAULT_CLOSED'} 773 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 774 775 @classmethod 776 def poll(cls, context): 777 if not PhysicButtonsPanel.poll_dyn_canvas_brush(context): 778 return False 779 780 return (context.engine in cls.COMPAT_ENGINES) 781 782 def draw(self, context): 783 layout = self.layout 784 layout.use_property_split = True 785 flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) 786 787 brush = context.dynamic_paint.brush_settings 788 789 col = flow.column() 790 col.prop(brush, "use_velocity_alpha") 791 col.prop(brush, "use_velocity_color") 792 793 col = flow.column() 794 col.prop(brush, "use_velocity_depth") 795 sub = col.column() 796 sub.active = (brush.use_velocity_alpha or brush.use_velocity_color or brush.use_velocity_depth) 797 sub.prop(brush, "velocity_max") 798 799 800class PHYSICS_PT_dp_brush_velocity_color_ramp(PhysicButtonsPanel, Panel): 801 bl_label = "Ramp" 802 bl_parent_id = "PHYSICS_PT_dp_brush_velocity" 803 bl_options = {'DEFAULT_CLOSED'} 804 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 805 806 @classmethod 807 def poll(cls, context): 808 if not PhysicButtonsPanel.poll_dyn_canvas_brush(context): 809 return False 810 811 return (context.engine in cls.COMPAT_ENGINES) 812 813 def draw(self, context): 814 layout = self.layout 815 816 brush = context.dynamic_paint.brush_settings 817 818 layout.template_color_ramp(brush, "velocity_ramp", expand=True) 819 820 821class PHYSICS_PT_dp_brush_velocity_smudge(PhysicButtonsPanel, Panel): 822 bl_label = "Smudge" 823 bl_parent_id = "PHYSICS_PT_dp_brush_velocity" 824 bl_options = {'DEFAULT_CLOSED'} 825 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 826 827 @classmethod 828 def poll(cls, context): 829 if not PhysicButtonsPanel.poll_dyn_canvas_brush(context): 830 return False 831 832 return (context.engine in cls.COMPAT_ENGINES) 833 834 def draw_header(self, context): 835 brush = context.dynamic_paint.brush_settings 836 837 self.layout.prop(brush, "use_smudge", text="") 838 839 def draw(self, context): 840 layout = self.layout 841 layout.use_property_split = True 842 843 brush = context.dynamic_paint.brush_settings 844 845 layout.active = brush.use_smudge 846 layout.prop(brush, "smudge_strength", text="Strength", slider=True) 847 848 849class PHYSICS_PT_dp_brush_wave(PhysicButtonsPanel, Panel): 850 bl_label = "Waves" 851 bl_parent_id = "PHYSICS_PT_dynamic_paint" 852 bl_options = {'DEFAULT_CLOSED'} 853 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 854 855 @classmethod 856 def poll(cls, context): 857 if not PhysicButtonsPanel.poll_dyn_canvas_brush(context): 858 return False 859 860 return (context.engine in cls.COMPAT_ENGINES) 861 862 def draw(self, context): 863 layout = self.layout 864 layout.use_property_split = True 865 866 brush = context.dynamic_paint.brush_settings 867 868 layout.prop(brush, "wave_type", text="Type") 869 870 flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) 871 872 if brush.wave_type != 'REFLECT': 873 col = flow.column() 874 col.prop(brush, "wave_factor") 875 876 col = flow.column() 877 col.prop(brush, "wave_clamp") 878 879 880classes = ( 881 PHYSICS_UL_dynapaint_surfaces, 882 PHYSICS_PT_dynamic_paint, 883 PHYSICS_PT_dynamic_paint_settings, 884 PHYSICS_PT_dp_surface_canvas, 885 PHYSICS_PT_dp_surface_canvas_paint_dissolve, 886 PHYSICS_PT_dp_surface_canvas_paint_dry, 887 PHYSICS_PT_dp_cache, 888 PHYSICS_PT_dp_effects, 889 PHYSICS_PT_dp_effects_spread, 890 PHYSICS_PT_dp_effects_drip, 891 PHYSICS_PT_dp_effects_drip_weights, 892 PHYSICS_PT_dp_effects_shrink, 893 PHYSICS_PT_dp_canvas_initial_color, 894 PHYSICS_PT_dp_brush_source, 895 PHYSICS_PT_dp_brush_source_color_ramp, 896 PHYSICS_PT_dp_brush_velocity, 897 PHYSICS_PT_dp_brush_velocity_color_ramp, 898 PHYSICS_PT_dp_brush_velocity_smudge, 899 PHYSICS_PT_dp_brush_wave, 900 PHYSICS_PT_dp_canvas_output, 901 PHYSICS_PT_dp_canvas_output_paintmaps, 902 PHYSICS_PT_dp_canvas_output_wetmaps, 903) 904 905 906if __name__ == "__main__": # only for live edit. 907 from bpy.utils import register_class 908 for cls in classes: 909 register_class(cls) 910