1 # ##### BEGIN GPL LICENSE BLOCK #####
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.
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.
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.
17 # ##### END GPL LICENSE BLOCK #####
21 from bpy.types import Panel
22 from rna_prop_ui import PropertyPanel
24 from bl_ui.properties_physics_common import (
27 basic_force_field_settings_ui,
28 basic_force_field_falloff_ui,
32 def particle_panel_enabled(context, psys):
35 phystype = psys.settings.physics_type
36 if psys.settings.type in {'EMITTER', 'REACTOR'} and phystype in {'NO', 'KEYED'}:
39 return (psys.point_cache.is_baked is False) and (not psys.is_edited) and (not context.particle_system_editable)
42 def particle_panel_poll(cls, context):
43 psys = context.particle_system
44 engine = context.scene.render.engine
48 settings = psys.settings
49 elif isinstance(context.space_data.pin_id, bpy.types.ParticleSettings):
50 settings = context.space_data.pin_id
55 return settings.is_fluid == False and (engine in cls.COMPAT_ENGINES)
58 def particle_get_settings(context):
59 if context.particle_system:
60 return context.particle_system.settings
61 elif isinstance(context.space_data.pin_id, bpy.types.ParticleSettings):
62 return context.space_data.pin_id
66 class ParticleButtonsPanel():
67 bl_space_type = 'PROPERTIES'
68 bl_region_type = 'WINDOW'
69 bl_context = "particle"
72 def poll(cls, context):
73 return particle_panel_poll(cls, context)
76 class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel):
78 bl_options = {'HIDE_HEADER'}
79 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
82 def poll(cls, context):
83 engine = context.scene.render.engine
84 return (context.particle_system or context.object or context.space_data.pin_id) and (engine in cls.COMPAT_ENGINES)
86 def draw(self, context):
89 if context.scene.render.engine == 'BLENDER_GAME':
90 layout.label("Not available in the Game Engine")
94 psys = context.particle_system
100 row.template_list(ob, "particle_systems", ob.particle_systems, "active_index", rows=2)
102 col = row.column(align=True)
103 col.operator("object.particle_system_add", icon='ZOOMIN', text="")
104 col.operator("object.particle_system_remove", icon='ZOOMOUT', text="")
107 part = particle_get_settings(context)
112 layout.template_ID(context.space_data, "pin_id")
115 layout.label(text="Settings used for fluid")
118 layout.prop(part, "type", text="Type")
120 elif not psys.settings:
121 split = layout.split(percentage=0.32)
124 col.label(text="Name:")
125 col.label(text="Settings:")
128 col.prop(psys, "name", text="")
129 col.template_ID(psys, "settings", new="particle.new")
133 split = layout.split(percentage=0.32)
135 col.label(text="Name:")
136 if part.is_fluid == False:
137 col.label(text="Settings:")
138 col.label(text="Type:")
141 col.prop(psys, "name", text="")
142 if part.is_fluid == False:
144 row.enabled = particle_panel_enabled(context, psys)
145 row.template_ID(psys, "settings", new="particle.new")
148 #row.label(text="Viewport")
149 #row.label(text="Render")
152 layout.label(text="{} fluid particles for this frame".format(str(part.count)))
156 row.enabled = particle_panel_enabled(context, psys)
157 row.prop(part, "type", text="")
158 row.prop(psys, "seed")
161 split = layout.split(percentage=0.65)
162 if part.type == 'HAIR':
163 if psys is not None and psys.is_edited:
164 split.operator("particle.edited_clear", text="Free Edit")
167 row.enabled = particle_panel_enabled(context, psys)
168 row.prop(part, "regrow_hair")
169 row.prop(part, "use_advanced_hair")
171 row.enabled = particle_panel_enabled(context, psys)
172 row.prop(part, "hair_step")
173 if psys is not None and psys.is_edited:
174 if psys.is_global_hair:
175 layout.operator("particle.connect_hair")
177 layout.operator("particle.disconnect_hair")
178 elif psys is not None and part.type == 'REACTOR':
179 split.enabled = particle_panel_enabled(context, psys)
180 split.prop(psys, "reactor_target_object")
181 split.prop(psys, "reactor_target_particle_system", text="Particle System")
184 class PARTICLE_PT_emission(ParticleButtonsPanel, Panel):
185 bl_label = "Emission"
186 COMPAT_ENGINES = {'BLENDER_RENDER'}
189 def poll(cls, context):
190 psys = context.particle_system
191 settings = particle_get_settings(context)
195 if settings.is_fluid:
197 if particle_panel_poll(PARTICLE_PT_emission, context):
198 return psys is None or not context.particle_system.point_cache.use_external
201 def draw(self, context):
204 psys = context.particle_system
205 part = particle_get_settings(context)
207 layout.enabled = particle_panel_enabled(context, psys) and (psys is None or not psys.has_multiple_caches)
210 row.active = part.distribution != 'GRID'
211 row.prop(part, "count")
213 if part.type == 'HAIR' and not part.use_advanced_hair:
214 row.prop(part, "hair_length")
217 if part.type != 'HAIR':
218 split = layout.split()
220 col = split.column(align=True)
221 col.prop(part, "frame_start")
222 col.prop(part, "frame_end")
224 col = split.column(align=True)
225 col.prop(part, "lifetime")
226 col.prop(part, "lifetime_random", slider=True)
228 layout.label(text="Emit From:")
229 layout.prop(part, "emit_from", expand=True)
232 if part.emit_from == 'VERT':
233 row.prop(part, "use_emit_random")
234 elif part.distribution == 'GRID':
235 row.prop(part, "invert_grid")
236 row.prop(part, "hexagonal_grid")
238 row.prop(part, "use_emit_random")
239 row.prop(part, "use_even_distribution")
241 if part.emit_from == 'FACE' or part.emit_from == 'VOLUME':
242 layout.prop(part, "distribution", expand=True)
245 if part.distribution == 'JIT':
246 row.prop(part, "userjit", text="Particles/Face")
247 row.prop(part, "jitter_factor", text="Jittering Amount", slider=True)
248 elif part.distribution == 'GRID':
249 row.prop(part, "grid_resolution")
250 row.prop(part, "grid_random", text="Random", slider=True)
253 class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, Panel):
254 bl_label = "Hair dynamics"
255 bl_options = {'DEFAULT_CLOSED'}
256 COMPAT_ENGINES = {'BLENDER_RENDER'}
259 def poll(cls, context):
260 psys = context.particle_system
261 engine = context.scene.render.engine
264 if psys.settings is None:
266 return psys.settings.type == 'HAIR' and (engine in cls.COMPAT_ENGINES)
268 def draw_header(self, context):
269 psys = context.particle_system
270 self.layout.prop(psys, "use_hair_dynamics", text="")
272 def draw(self, context):
275 psys = context.particle_system
280 cloth = psys.cloth.settings
282 layout.enabled = psys.use_hair_dynamics and psys.point_cache.is_baked == False
284 split = layout.split()
287 col.label(text="Material:")
288 sub = col.column(align=True)
289 sub.prop(cloth, "pin_stiffness", text="Stiffness")
290 sub.prop(cloth, "mass")
291 sub.prop(cloth, "bending_stiffness", text="Bending")
292 sub.prop(cloth, "internal_friction", slider=True)
293 sub.prop(cloth, "collider_friction", slider=True)
296 col.label(text="Damping:")
297 sub = col.column(align=True)
298 sub.prop(cloth, "spring_damping", text="Spring")
299 sub.prop(cloth, "air_damping", text="Air")
301 col.label(text="Quality:")
302 col.prop(cloth, "quality", text="Steps", slider=True)
305 class PARTICLE_PT_cache(ParticleButtonsPanel, Panel):
307 bl_options = {'DEFAULT_CLOSED'}
308 COMPAT_ENGINES = {'BLENDER_RENDER'}
311 def poll(cls, context):
312 psys = context.particle_system
313 engine = context.scene.render.engine
316 if psys.settings is None:
318 if psys.settings.is_fluid:
320 phystype = psys.settings.physics_type
321 if phystype == 'NO' or phystype == 'KEYED':
323 return (psys.settings.type in {'EMITTER', 'REACTOR'} or (psys.settings.type == 'HAIR' and (psys.use_hair_dynamics or psys.point_cache.is_baked))) and engine in cls.COMPAT_ENGINES
325 def draw(self, context):
326 psys = context.particle_system
328 point_cache_ui(self, context, psys.point_cache, True, 'HAIR' if (psys.settings.type == 'HAIR') else 'PSYS')
331 class PARTICLE_PT_velocity(ParticleButtonsPanel, Panel):
332 bl_label = "Velocity"
333 COMPAT_ENGINES = {'BLENDER_RENDER'}
336 def poll(cls, context):
337 if particle_panel_poll(PARTICLE_PT_velocity, context):
338 psys = context.particle_system
339 settings = particle_get_settings(context)
341 if settings.type == 'HAIR' and not settings.use_advanced_hair:
343 return settings.physics_type != 'BOIDS' and (psys is None or not psys.point_cache.use_external)
347 def draw(self, context):
350 psys = context.particle_system
351 part = particle_get_settings(context)
353 layout.enabled = particle_panel_enabled(context, psys)
355 split = layout.split()
358 col.label(text="Emitter Geometry:")
359 col.prop(part, "normal_factor")
360 sub = col.column(align=True)
361 sub.prop(part, "tangent_factor")
362 sub.prop(part, "tangent_phase", slider=True)
365 col.label(text="Emitter Object:")
366 col.prop(part, "object_align_factor", text="")
368 layout.label(text="Other:")
370 if part.emit_from == 'PARTICLE':
371 row.prop(part, "particle_factor")
373 row.prop(part, "object_factor", slider=True)
374 row.prop(part, "factor_random")
376 #if part.type=='REACTOR':
377 # sub.prop(part, "reactor_factor")
378 # sub.prop(part, "reaction_shape", slider=True)
381 class PARTICLE_PT_rotation(ParticleButtonsPanel, Panel):
382 bl_label = "Rotation"
383 bl_options = {'DEFAULT_CLOSED'}
384 COMPAT_ENGINES = {'BLENDER_RENDER'}
387 def poll(cls, context):
388 if particle_panel_poll(PARTICLE_PT_rotation, context):
389 psys = context.particle_system
390 settings = particle_get_settings(context)
392 if settings.type == 'HAIR' and not settings.use_advanced_hair:
394 return settings.physics_type != 'BOIDS' and (psys is None or not psys.point_cache.use_external)
398 def draw_header(self, context):
399 psys = context.particle_system
403 part = context.space_data.pin_id
405 self.layout.prop(part, "use_rotations", text="")
407 def draw(self, context):
410 psys = context.particle_system
414 part = context.space_data.pin_id
416 layout.enabled = particle_panel_enabled(context, psys) and part.use_rotations
418 layout.label(text="Initial Orientation:")
420 split = layout.split()
422 col = split.column(align=True)
423 col.prop(part, "rotation_mode", text="")
424 col.prop(part, "rotation_factor_random", slider=True, text="Random")
426 col = split.column(align=True)
427 col.prop(part, "phase_factor", slider=True)
428 col.prop(part, "phase_factor_random", text="Random", slider=True)
430 if part.type != 'HAIR':
431 layout.label(text="Angular Velocity:")
433 split = layout.split()
434 col = split.column(align=True)
435 col.prop(part, "angular_velocity_mode", text="")
437 sub.active = part.angular_velocity_mode != 'NONE'
438 sub.prop(part, "angular_velocity_factor", text="")
441 col.prop(part, "use_dynamic_rotation")
444 class PARTICLE_PT_physics(ParticleButtonsPanel, Panel):
446 COMPAT_ENGINES = {'BLENDER_RENDER'}
449 def poll(cls, context):
450 if particle_panel_poll(PARTICLE_PT_physics, context):
451 psys = context.particle_system
452 settings = particle_get_settings(context)
454 if settings.type == 'HAIR' and not settings.use_advanced_hair:
456 return psys is None or not psys.point_cache.use_external
460 def draw(self, context):
463 psys = context.particle_system
464 part = particle_get_settings(context)
466 layout.enabled = particle_panel_enabled(context, psys)
468 layout.prop(part, "physics_type", expand=True)
471 col = row.column(align=True)
472 col.prop(part, "particle_size")
473 col.prop(part, "size_random", slider=True)
475 if part.physics_type != 'NO':
476 col = row.column(align=True)
477 col.prop(part, "mass")
478 col.prop(part, "use_multiply_size_mass", text="Multiply mass with size")
480 if part.physics_type in {'NEWTON', 'FLUID'}:
481 split = layout.split()
484 col.label(text="Forces:")
485 col.prop(part, "brownian_factor")
486 col.prop(part, "drag_factor", slider=True)
487 col.prop(part, "damping", slider=True)
490 col.label(text="Integration:")
491 col.prop(part, "integrator", text="")
492 col.prop(part, "timestep")
494 if part.adaptive_subframes:
495 sub.prop(part, "courant_target", text="Threshold")
497 sub.prop(part, "subframes")
498 sub.prop(part, "adaptive_subframes", text="")
501 row.prop(part, "use_size_deflect")
502 row.prop(part, "use_die_on_collision")
504 if part.physics_type == 'FLUID':
507 split = layout.split()
510 col.label(text="Fluid properties:")
511 col.prop(fluid, "stiffness", text="Stiffness")
512 col.prop(fluid, "linear_viscosity", text="Viscosity")
513 col.prop(fluid, "buoyancy", text="Buoyancy", slider=True)
516 col.label(text="Advanced:")
519 sub.prop(fluid, "repulsion", slider=fluid.factor_repulsion)
520 sub.prop(fluid, "factor_repulsion", text="")
523 sub.prop(fluid, "stiff_viscosity", slider=fluid.factor_stiff_viscosity)
524 sub.prop(fluid, "factor_stiff_viscosity", text="")
527 sub.prop(fluid, "fluid_radius", slider=fluid.factor_radius)
528 sub.prop(fluid, "factor_radius", text="")
531 sub.prop(fluid, "rest_density", slider=fluid.factor_density)
532 sub.prop(fluid, "factor_density", text="")
534 split = layout.split()
537 col.label(text="Springs:")
538 col.prop(fluid, "spring_force", text="Force")
539 col.prop(fluid, "use_viscoelastic_springs")
540 sub = col.column(align=True)
541 sub.active = fluid.use_viscoelastic_springs
542 sub.prop(fluid, "yield_ratio", slider=True)
543 sub.prop(fluid, "plasticity", slider=True)
546 col.label(text="Advanced:")
548 sub.prop(fluid, "rest_length", slider=fluid.factor_rest_length)
549 sub.prop(fluid, "factor_rest_length", text="")
552 sub.active = fluid.use_viscoelastic_springs
553 sub.prop(fluid, "use_initial_rest_length")
554 sub.prop(fluid, "spring_frames", text="Frames")
556 elif part.physics_type == 'KEYED':
557 split = layout.split()
562 col.active = not psys.use_keyed_timing
563 col.prop(part, "keyed_loops", text="Loops")
565 row.prop(psys, "use_keyed_timing", text="Use Timing")
567 layout.label(text="Keys:")
568 elif part.physics_type == 'BOIDS':
572 row.prop(boids, "use_flight")
573 row.prop(boids, "use_land")
574 row.prop(boids, "use_climb")
576 split = layout.split()
579 col = sub.column(align=True)
580 col.active = boids.use_flight
581 col.prop(boids, "air_speed_max")
582 col.prop(boids, "air_speed_min", slider=True)
583 col.prop(boids, "air_acc_max", slider=True)
584 col.prop(boids, "air_ave_max", slider=True)
585 col.prop(boids, "air_personal_space")
587 row.active = (boids.use_land or boids.use_climb) and boids.use_flight
588 row.prop(boids, "land_smooth")
591 col = sub.column(align=True)
592 col.active = boids.use_land or boids.use_climb
593 col.prop(boids, "land_speed_max")
594 col.prop(boids, "land_jump_speed")
595 col.prop(boids, "land_acc_max", slider=True)
596 col.prop(boids, "land_ave_max", slider=True)
597 col.prop(boids, "land_personal_space")
598 col.prop(boids, "land_stick_force")
602 col = row.column(align=True)
603 col.label(text="Battle:")
604 col.prop(boids, "health")
605 col.prop(boids, "strength")
606 col.prop(boids, "aggression")
607 col.prop(boids, "accuracy")
608 col.prop(boids, "range")
611 col.label(text="Misc:")
612 col.prop(boids, "bank", slider=True)
613 col.prop(boids, "pitch", slider=True)
614 col.prop(boids, "height", slider=True)
616 if psys and part.physics_type in {'KEYED', 'BOIDS', 'FLUID'}:
617 if part.physics_type == 'BOIDS':
618 layout.label(text="Relations:")
619 elif part.physics_type == 'FLUID':
620 layout.label(text="Fluid interaction:")
623 row.template_list(psys, "targets", psys, "active_particle_target_index")
627 subsub = sub.column(align=True)
628 subsub.operator("particle.new_target", icon='ZOOMIN', text="")
629 subsub.operator("particle.target_remove", icon='ZOOMOUT', text="")
631 subsub = sub.column(align=True)
632 subsub.operator("particle.target_move_up", icon='MOVE_UP_VEC', text="")
633 subsub.operator("particle.target_move_down", icon='MOVE_DOWN_VEC', text="")
635 key = psys.active_particle_target
638 if part.physics_type == 'KEYED':
641 #col.alert = key.valid
642 col.prop(key, "object", text="")
643 col.prop(key, "system", text="System")
645 col.active = psys.use_keyed_timing
646 col.prop(key, "time")
647 col.prop(key, "duration")
648 elif part.physics_type == 'BOIDS':
651 #sub.alert = key.valid
652 sub.prop(key, "object", text="")
653 sub.prop(key, "system", text="System")
655 layout.prop(key, "alliance", expand=True)
656 elif part.physics_type == 'FLUID':
659 #sub.alert = key.valid
660 sub.prop(key, "object", text="")
661 sub.prop(key, "system", text="System")
664 class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel):
665 bl_label = "Boid Brain"
666 COMPAT_ENGINES = {'BLENDER_RENDER'}
669 def poll(cls, context):
670 psys = context.particle_system
671 settings = particle_get_settings(context)
672 engine = context.scene.render.engine
676 if psys is not None and psys.point_cache.use_external:
678 return settings.physics_type == 'BOIDS' and engine in cls.COMPAT_ENGINES
680 def draw(self, context):
683 boids = particle_get_settings(context).boids
685 layout.enabled = particle_panel_enabled(context, context.particle_system)
687 # Currently boids can only use the first state so these are commented out for now.
689 #row.template_list(boids, "states", boids, "active_boid_state_index", compact="True")
691 #sub = col.row(align=True)
692 #sub.operator("boid.state_add", icon='ZOOMIN', text="")
693 #sub.operator("boid.state_del", icon='ZOOMOUT', text="")
694 #sub = row.row(align=True)
695 #sub.operator("boid.state_move_up", icon='MOVE_UP_VEC', text="")
696 #sub.operator("boid.state_move_down", icon='MOVE_DOWN_VEC', text="")
698 state = boids.active_boid_state
700 #layout.prop(state, "name", text="State name")
703 row.prop(state, "ruleset_type")
704 if state.ruleset_type == 'FUZZY':
705 row.prop(state, "rule_fuzzy", slider=True)
710 row.template_list(state, "rules", state, "active_boid_rule_index")
714 subsub = sub.column(align=True)
715 subsub.operator_menu_enum("boid.rule_add", "type", icon='ZOOMIN', text="")
716 subsub.operator("boid.rule_del", icon='ZOOMOUT', text="")
718 subsub = sub.column(align=True)
719 subsub.operator("boid.rule_move_up", icon='MOVE_UP_VEC', text="")
720 subsub.operator("boid.rule_move_down", icon='MOVE_DOWN_VEC', text="")
722 rule = state.active_boid_rule
726 row.prop(rule, "name", text="")
727 #somebody make nice icons for boids here please! -jahka
728 row.prop(rule, "use_in_air", icon='MOVE_UP_VEC', text="")
729 row.prop(rule, "use_on_land", icon='MOVE_DOWN_VEC', text="")
733 if rule.type == 'GOAL':
734 row.prop(rule, "object")
736 row.prop(rule, "use_predict")
737 elif rule.type == 'AVOID':
738 row.prop(rule, "object")
740 row.prop(rule, "use_predict")
741 row.prop(rule, "fear_factor")
742 elif rule.type == 'FOLLOW_PATH':
743 row.label(text="Not yet functional")
744 elif rule.type == 'AVOID_COLLISION':
745 row.prop(rule, "use_avoid")
746 row.prop(rule, "use_avoid_collision")
747 row.prop(rule, "look_ahead")
748 elif rule.type == 'FOLLOW_LEADER':
749 row.prop(rule, "object", text="")
750 row.prop(rule, "distance")
752 row.prop(rule, "use_line")
754 sub.active = rule.line
755 sub.prop(rule, "queue_count")
756 elif rule.type == 'AVERAGE_SPEED':
757 row.prop(rule, "speed", slider=True)
758 row.prop(rule, "wander", slider=True)
759 row.prop(rule, "level", slider=True)
760 elif rule.type == 'FIGHT':
761 row.prop(rule, "distance")
762 row.prop(rule, "flee_distance")
765 class PARTICLE_PT_render(ParticleButtonsPanel, Panel):
767 COMPAT_ENGINES = {'BLENDER_RENDER'}
770 def poll(cls, context):
771 settings = particle_get_settings(context)
772 engine = context.scene.render.engine
776 return engine in cls.COMPAT_ENGINES
778 def draw(self, context):
781 psys = context.particle_system
782 part = particle_get_settings(context)
785 row.prop(part, "material")
787 row.prop(psys, "parent")
789 split = layout.split()
792 col.prop(part, "use_render_emitter")
793 col.prop(part, "use_parent_particles")
796 col.prop(part, "show_unborn")
797 col.prop(part, "use_dead")
799 layout.prop(part, "render_type", expand=True)
801 split = layout.split()
805 if part.render_type == 'LINE':
806 col.prop(part, "line_length_tail")
807 col.prop(part, "line_length_head")
809 split.prop(part, "use_velocity_length")
810 elif part.render_type == 'PATH':
811 col.prop(part, "use_strand_primitive")
813 sub.active = (part.use_strand_primitive is False)
814 sub.prop(part, "use_render_adaptive")
816 sub.active = part.use_render_adaptive or part.use_strand_primitive == True
817 sub.prop(part, "adaptive_angle")
819 sub.active = (part.use_render_adaptive is True and part.use_strand_primitive is False)
820 sub.prop(part, "adaptive_pixel")
821 col.prop(part, "use_hair_bspline")
822 col.prop(part, "render_step", text="Steps")
825 col.label(text="Timing:")
826 col.prop(part, "use_absolute_path_time")
827 col.prop(part, "path_start", text="Start", slider=not part.use_absolute_path_time)
828 col.prop(part, "path_end", text="End", slider=not part.use_absolute_path_time)
829 col.prop(part, "length_random", text="Random", slider=True)
834 if part.type == 'HAIR' and part.use_strand_primitive == True and part.child_type == 'INTERPOLATED':
835 layout.prop(part, "use_simplify")
836 if part.use_simplify == True:
838 row.prop(part, "simplify_refsize")
839 row.prop(part, "simplify_rate")
840 row.prop(part, "simplify_transition")
842 row.prop(part, "use_simplify_viewport")
844 sub.active = part.use_simplify_viewport == True
845 sub.prop(part, "simplify_viewport")
847 elif part.render_type == 'OBJECT':
848 col.prop(part, "dupli_object")
850 sub.prop(part, "use_global_dupli")
851 sub.prop(part, "use_rotation_dupli")
852 sub.prop(part, "use_scale_dupli")
853 elif part.render_type == 'GROUP':
854 col.prop(part, "dupli_group")
855 split = layout.split()
858 col.prop(part, "use_whole_group")
860 sub.active = (part.use_whole_group is False)
861 sub.prop(part, "use_group_pick_random")
862 sub.prop(part, "use_group_count")
866 sub.active = (part.use_whole_group is False)
867 sub.prop(part, "use_global_dupli")
868 sub.prop(part, "use_rotation_dupli")
869 sub.prop(part, "use_scale_dupli")
871 if part.use_group_count and not part.use_whole_group:
873 row.template_list(part, "dupli_weights", part, "active_dupliweight_index")
877 subsub = sub.column(align=True)
878 subsub.operator("particle.dupliob_copy", icon='ZOOMIN', text="")
879 subsub.operator("particle.dupliob_remove", icon='ZOOMOUT', text="")
880 subsub.operator("particle.dupliob_move_up", icon='MOVE_UP_VEC', text="")
881 subsub.operator("particle.dupliob_move_down", icon='MOVE_DOWN_VEC', text="")
883 weight = part.active_dupliweight
886 row.prop(weight, "count")
888 elif part.render_type == 'BILLBOARD':
891 col.label(text="Align:")
894 row.prop(part, "billboard_align", expand=True)
895 row.prop(part, "lock_billboard", text="Lock")
897 row.prop(part, "billboard_object")
900 col = row.column(align=True)
901 col.label(text="Tilt:")
902 col.prop(part, "billboard_tilt", text="Angle", slider=True)
903 col.prop(part, "billboard_tilt_random", text="Random", slider=True)
905 col.prop(part, "billboard_offset")
909 col.prop(part, "billboard_size", text="Scale")
910 if part.billboard_align == 'VEL':
911 col = row.column(align=True)
912 col.label("Velocity Scale:")
913 col.prop(part, "billboard_velocity_head", text="Head")
914 col.prop(part, "billboard_velocity_tail", text="Tail")
917 col = layout.column()
918 col.prop_search(psys, "billboard_normal_uv", ob.data, "uv_textures")
919 col.prop_search(psys, "billboard_time_index_uv", ob.data, "uv_textures")
921 split = layout.split(percentage=0.33)
922 split.label(text="Split UVs:")
923 split.prop(part, "billboard_uv_split", text="Number of splits")
926 col = layout.column()
927 col.active = part.billboard_uv_split > 1
928 col.prop_search(psys, "billboard_split_uv", ob.data, "uv_textures")
931 row.label(text="Animate:")
932 row.prop(part, "billboard_animation", text="")
933 row.label(text="Offset:")
934 row.prop(part, "billboard_offset_split", text="")
936 if part.render_type == 'HALO' or part.render_type == 'LINE' or part.render_type == 'BILLBOARD':
939 col.prop(part, "trail_count")
940 if part.trail_count > 1:
941 col.prop(part, "use_absolute_path_time", text="Length in frames")
943 col.prop(part, "path_end", text="Length", slider=not part.use_absolute_path_time)
944 col.prop(part, "length_random", text="Random", slider=True)
949 if part.render_type in {'OBJECT', 'GROUP'} and not part.use_advanced_hair:
950 row = layout.row(align=True)
951 row.prop(part, "particle_size")
952 row.prop(part, "size_random", slider=True)
955 class PARTICLE_PT_draw(ParticleButtonsPanel, Panel):
957 bl_options = {'DEFAULT_CLOSED'}
958 COMPAT_ENGINES = {'BLENDER_RENDER'}
961 def poll(cls, context):
962 settings = particle_get_settings(context)
963 engine = context.scene.render.engine
966 return engine in cls.COMPAT_ENGINES
968 def draw(self, context):
971 psys = context.particle_system
972 part = particle_get_settings(context)
975 row.prop(part, "draw_method", expand=True)
977 if part.draw_method == 'NONE' or (part.render_type == 'NONE' and part.draw_method == 'RENDER'):
980 path = (part.render_type == 'PATH' and part.draw_method == 'RENDER') or part.draw_method == 'PATH'
983 row.prop(part, "draw_percentage", slider=True)
984 if part.draw_method != 'RENDER' or part.render_type == 'HALO':
985 row.prop(part, "draw_size")
989 if part.draw_percentage != 100 and psys is not None:
990 if part.type == 'HAIR':
991 if psys.use_hair_dynamics and psys.point_cache.is_baked == False:
992 layout.row().label(text="Display percentage makes dynamics inaccurate without baking!")
994 phystype = part.physics_type
995 if phystype != 'NO' and phystype != 'KEYED' and psys.point_cache.is_baked == False:
996 layout.row().label(text="Display percentage makes dynamics inaccurate without baking!")
1000 col.prop(part, "show_size")
1001 col.prop(part, "show_velocity")
1002 col.prop(part, "show_number")
1003 if part.physics_type == 'BOIDS':
1004 col.prop(part, "show_health")
1006 col = row.column(align=True)
1007 col.label(text="Color:")
1008 col.prop(part, "draw_color", text="")
1010 sub.active = (part.draw_color in {'VELOCITY', 'ACCELERATION'})
1011 sub.prop(part, "color_maximum", text="Max")
1014 col.prop(part, "draw_step")
1017 class PARTICLE_PT_children(ParticleButtonsPanel, Panel):
1018 bl_label = "Children"
1019 bl_options = {'DEFAULT_CLOSED'}
1020 COMPAT_ENGINES = {'BLENDER_RENDER'}
1023 def poll(cls, context):
1024 return particle_panel_poll(cls, context)
1026 def draw(self, context):
1027 layout = self.layout
1029 psys = context.particle_system
1030 part = particle_get_settings(context)
1032 layout.row().prop(part, "child_type", expand=True)
1034 if part.child_type == 'NONE':
1039 col = row.column(align=True)
1040 col.prop(part, "child_nbr", text="Display")
1041 col.prop(part, "rendered_child_count", text="Render")
1043 if part.child_type == 'INTERPOLATED':
1046 col.prop(psys, "child_seed", text="Seed")
1047 col.prop(part, "virtual_parents", slider=True)
1048 col.prop(part, "create_long_hair_children")
1050 col = row.column(align=True)
1051 col.prop(part, "child_size", text="Size")
1052 col.prop(part, "child_size_random", text="Random")
1054 split = layout.split()
1056 col = split.column()
1057 col.label(text="Effects:")
1059 sub = col.column(align=True)
1060 sub.prop(part, "clump_factor", slider=True)
1061 sub.prop(part, "clump_shape", slider=True)
1063 sub = col.column(align=True)
1064 sub.prop(part, "child_length", slider=True)
1065 sub.prop(part, "child_length_threshold", slider=True)
1067 if part.child_type == 'SIMPLE':
1068 sub = col.column(align=True)
1069 sub.prop(part, "child_radius", text="Radius")
1070 sub.prop(part, "child_roundness", text="Roundness", slider=True)
1072 sub.prop(psys, "child_seed", text="Seed")
1073 elif part.virtual_parents > 0.0:
1074 sub = col.column(align=True)
1075 sub.label(text="Parting not")
1076 sub.label(text="available with")
1077 sub.label(text="virtual parents")
1079 sub = col.column(align=True)
1080 sub.prop(part, "child_parting_factor", text="Parting", slider=True)
1081 sub.prop(part, "child_parting_min", text="Min")
1082 sub.prop(part, "child_parting_max", text="Max")
1084 col = split.column()
1085 col.label(text="Roughness:")
1087 sub = col.column(align=True)
1088 sub.prop(part, "roughness_1", text="Uniform")
1089 sub.prop(part, "roughness_1_size", text="Size")
1091 sub = col.column(align=True)
1092 sub.prop(part, "roughness_endpoint", "Endpoint")
1093 sub.prop(part, "roughness_end_shape")
1095 sub = col.column(align=True)
1096 sub.prop(part, "roughness_2", text="Random")
1097 sub.prop(part, "roughness_2_size", text="Size")
1098 sub.prop(part, "roughness_2_threshold", slider=True)
1100 layout.row().label(text="Kink:")
1101 layout.row().prop(part, "kink", expand=True)
1103 split = layout.split()
1104 split.active = part.kink != 'NO'
1106 col = split.column()
1107 sub = col.column(align=True)
1108 sub.prop(part, "kink_amplitude")
1109 sub.prop(part, "kink_amplitude_clump", text="Clump", slider=True)
1110 col.prop(part, "kink_flat", slider=True)
1111 col = split.column()
1112 sub = col.column(align=True)
1113 sub.prop(part, "kink_frequency")
1114 sub.prop(part, "kink_shape", slider=True)
1117 class PARTICLE_PT_field_weights(ParticleButtonsPanel, Panel):
1118 bl_label = "Field Weights"
1119 bl_options = {'DEFAULT_CLOSED'}
1120 COMPAT_ENGINES = {'BLENDER_RENDER'}
1123 def poll(cls, context):
1124 return particle_panel_poll(cls, context)
1126 def draw(self, context):
1127 part = particle_get_settings(context)
1128 effector_weights_ui(self, context, part.effector_weights)
1130 if part.type == 'HAIR':
1131 row = self.layout.row()
1132 row.prop(part.effector_weights, "apply_to_hair_growing")
1133 row.prop(part, "apply_effector_to_children")
1134 row = self.layout.row()
1135 row.prop(part, "effect_hair", slider=True)
1138 class PARTICLE_PT_force_fields(ParticleButtonsPanel, Panel):
1139 bl_label = "Force Field Settings"
1140 bl_options = {'DEFAULT_CLOSED'}
1141 COMPAT_ENGINES = {'BLENDER_RENDER'}
1143 def draw(self, context):
1144 layout = self.layout
1146 part = particle_get_settings(context)
1149 row.prop(part, "use_self_effect")
1150 row.prop(part, "effector_amount", text="Amount")
1152 split = layout.split(percentage=0.2)
1153 split.label(text="Type 1:")
1154 split.prop(part.force_field_1, "type", text="")
1155 basic_force_field_settings_ui(self, context, part.force_field_1)
1156 if part.force_field_1.type != 'NONE':
1157 layout.label(text="Falloff:")
1158 basic_force_field_falloff_ui(self, context, part.force_field_1)
1160 if part.force_field_1.type != 'NONE':
1161 layout.label(text="")
1163 split = layout.split(percentage=0.2)
1164 split.label(text="Type 2:")
1165 split.prop(part.force_field_2, "type", text="")
1166 basic_force_field_settings_ui(self, context, part.force_field_2)
1167 if part.force_field_2.type != 'NONE':
1168 layout.label(text="Falloff:")
1169 basic_force_field_falloff_ui(self, context, part.force_field_2)
1172 class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, Panel):
1173 bl_label = "Vertex Groups"
1174 bl_options = {'DEFAULT_CLOSED'}
1175 COMPAT_ENGINES = {'BLENDER_RENDER'}
1178 def poll(cls, context):
1179 if context.particle_system is None:
1181 return particle_panel_poll(cls, context)
1183 def draw(self, context):
1184 layout = self.layout
1187 psys = context.particle_system
1189 split = layout.split(percentage=0.85)
1191 col = split.column()
1192 col.label(text="Vertex Group:")
1193 col.prop_search(psys, "vertex_group_density", ob, "vertex_groups", text="Density")
1194 col.prop_search(psys, "vertex_group_length", ob, "vertex_groups", text="Length")
1195 col.prop_search(psys, "vertex_group_clump", ob, "vertex_groups", text="Clump")
1196 col.prop_search(psys, "vertex_group_kink", ob, "vertex_groups", text="Kink")
1197 col.prop_search(psys, "vertex_group_roughness_1", ob, "vertex_groups", text="Roughness 1")
1198 col.prop_search(psys, "vertex_group_roughness_2", ob, "vertex_groups", text="Roughness 2")
1199 col.prop_search(psys, "vertex_group_roughness_end", ob, "vertex_groups", text="Roughness End")
1201 col = split.column()
1202 col.label(text="Negate:")
1203 col.alignment = 'RIGHT'
1204 col.prop(psys, "invert_vertex_group_density", text="")
1205 col.prop(psys, "invert_vertex_group_length", text="")
1206 col.prop(psys, "invert_vertex_group_clump", text="")
1207 col.prop(psys, "invert_vertex_group_kink", text="")
1208 col.prop(psys, "invert_vertex_group_roughness_1", text="")
1209 col.prop(psys, "invert_vertex_group_roughness_2", text="")
1210 col.prop(psys, "invert_vertex_group_roughness_end", text="")
1212 # Commented out vertex groups don't work and are still waiting for better implementation
1213 # row = layout.row()
1214 # row.prop_search(psys, "vertex_group_velocity", ob, "vertex_groups", text="Velocity")
1215 # row.prop(psys, "invert_vertex_group_velocity", text="")
1217 # row = layout.row()
1218 # row.prop_search(psys, "vertex_group_size", ob, "vertex_groups", text="Size")
1219 # row.prop(psys, "invert_vertex_group_size", text="")
1221 # row = layout.row()
1222 # row.prop_search(psys, "vertex_group_tangent", ob, "vertex_groups", text="Tangent")
1223 # row.prop(psys, "invert_vertex_group_tangent", text="")
1225 # row = layout.row()
1226 # row.prop_search(psys, "vertex_group_rotation", ob, "vertex_groups", text="Rotation")
1227 # row.prop(psys, "invert_vertex_group_rotation", text="")
1229 # row = layout.row()
1230 # row.prop_search(psys, "vertex_group_field", ob, "vertex_groups", text="Field")
1231 # row.prop(psys, "invert_vertex_group_field", text="")
1234 class PARTICLE_PT_custom_props(ParticleButtonsPanel, PropertyPanel, Panel):
1235 COMPAT_ENGINES = {'BLENDER_RENDER'}
1236 _context_path = "particle_system.settings"
1237 _property_type = bpy.types.ParticleSettings
1239 if __name__ == "__main__": # only for live edit.
1240 bpy.utils.register_module(__name__)