Removed most partical-related code from UI scripts.

There are a lot of cases here where deciding for removal is a bit tricky.
Many features have options for "use_particles" and similar settings. Only
features which actually store a particle object reference or work on actual
particle data have been removed.
This commit is contained in:
Lukas Tönne
2016-04-12 16:28:00 +02:00
parent 29a792a75b
commit bcd12bf64d
18 changed files with 24 additions and 2035 deletions

View File

@@ -1,17 +0,0 @@
import bpy
psys = bpy.context.particle_system
cloth = bpy.context.particle_system.cloth
settings = bpy.context.particle_system.cloth.settings
collision = bpy.context.particle_system.cloth.collision_settings
settings.quality = 5
settings.mass = 0.30000001192092896
settings.bending_stiffness = 0.5
psys.settings.bending_random = 0.0
settings.bending_damping = 0.5
settings.air_damping = 1.0
settings.internal_friction = 0.0
settings.density_target = 0.0
settings.density_strength = 0.0
settings.voxel_cell_size = 0.10000000149011612
settings.pin_stiffness = 0.0

View File

@@ -47,239 +47,6 @@ def object_ensure_material(obj, mat_name):
return mat
class QuickFur(Operator):
bl_idname = "object.quick_fur"
bl_label = "Quick Fur"
bl_options = {'REGISTER', 'UNDO'}
density = EnumProperty(
name="Fur Density",
items=(('LIGHT', "Light", ""),
('MEDIUM', "Medium", ""),
('HEAVY', "Heavy", "")),
default='MEDIUM',
)
view_percentage = IntProperty(
name="View %",
min=1, max=100,
soft_min=1, soft_max=100,
default=10,
)
length = FloatProperty(
name="Length",
min=0.001, max=100,
soft_min=0.01, soft_max=10,
default=0.1,
)
def execute(self, context):
fake_context = context.copy()
mesh_objects = [obj for obj in context.selected_objects
if obj.type == 'MESH' and obj.mode == 'OBJECT']
if not mesh_objects:
self.report({'ERROR'}, "Select at least one mesh object")
return {'CANCELLED'}
mat = bpy.data.materials.new("Fur Material")
mat.strand.tip_size = 0.25
mat.strand.blend_distance = 0.5
for obj in mesh_objects:
fake_context["object"] = obj
bpy.ops.object.particle_system_add(fake_context)
psys = obj.particle_systems[-1]
psys.settings.type = 'HAIR'
if self.density == 'LIGHT':
psys.settings.count = 100
elif self.density == 'MEDIUM':
psys.settings.count = 1000
elif self.density == 'HEAVY':
psys.settings.count = 10000
psys.settings.child_nbr = self.view_percentage
psys.settings.hair_length = self.length
psys.settings.use_strand_primitive = True
psys.settings.use_hair_bspline = True
psys.settings.child_type = 'INTERPOLATED'
obj.data.materials.append(mat)
psys.settings.material = len(obj.data.materials)
return {'FINISHED'}
class QuickExplode(Operator):
bl_idname = "object.quick_explode"
bl_label = "Quick Explode"
bl_options = {'REGISTER', 'UNDO'}
style = EnumProperty(
name="Explode Style",
items=(('EXPLODE', "Explode", ""),
('BLEND', "Blend", "")),
default='EXPLODE',
)
amount = IntProperty(
name="Amount of pieces",
min=2, max=10000,
soft_min=2, soft_max=10000,
default=100,
)
frame_duration = IntProperty(
name="Duration",
min=1, max=300000,
soft_min=1, soft_max=10000,
default=50,
)
frame_start = IntProperty(
name="Start Frame",
min=1, max=300000,
soft_min=1, soft_max=10000,
default=1,
)
frame_end = IntProperty(
name="End Frame",
min=1, max=300000,
soft_min=1, soft_max=10000,
default=10,
)
velocity = FloatProperty(
name="Outwards Velocity",
min=0, max=300000,
soft_min=0, soft_max=10,
default=1,
)
fade = BoolProperty(
name="Fade",
description="Fade the pieces over time",
default=True,
)
def execute(self, context):
fake_context = context.copy()
obj_act = context.active_object
if obj_act is None or obj_act.type != 'MESH':
self.report({'ERROR'}, "Active object is not a mesh")
return {'CANCELLED'}
mesh_objects = [obj for obj in context.selected_objects
if obj.type == 'MESH' and obj != obj_act]
mesh_objects.insert(0, obj_act)
if self.style == 'BLEND' and len(mesh_objects) != 2:
self.report({'ERROR'}, "Select two mesh objects")
self.style = 'EXPLODE'
return {'CANCELLED'}
elif not mesh_objects:
self.report({'ERROR'}, "Select at least one mesh object")
return {'CANCELLED'}
for obj in mesh_objects:
if obj.particle_systems:
self.report({'ERROR'},
"Object %r already has a "
"particle system" % obj.name)
return {'CANCELLED'}
if self.fade:
tex = bpy.data.textures.new("Explode fade", 'BLEND')
tex.use_color_ramp = True
if self.style == 'BLEND':
tex.color_ramp.elements[0].position = 0.333
tex.color_ramp.elements[1].position = 0.666
tex.color_ramp.elements[0].color[3] = 1.0
tex.color_ramp.elements[1].color[3] = 0.0
if self.style == 'BLEND':
from_obj = mesh_objects[1]
to_obj = mesh_objects[0]
for obj in mesh_objects:
fake_context["object"] = obj
bpy.ops.object.particle_system_add(fake_context)
settings = obj.particle_systems[-1].settings
settings.count = self.amount
settings.frame_start = self.frame_start
settings.frame_end = self.frame_end - self.frame_duration
settings.lifetime = self.frame_duration
settings.normal_factor = self.velocity
settings.render_type = 'NONE'
explode = obj.modifiers.new(name='Explode', type='EXPLODE')
explode.use_edge_cut = True
if self.fade:
explode.show_dead = False
uv = obj.data.uv_textures.new("Explode fade")
explode.particle_uv = uv.name
mat = object_ensure_material(obj, "Explode Fade")
mat.use_transparency = True
mat.use_transparent_shadows = True
mat.alpha = 0.0
mat.specular_alpha = 0.0
tex_slot = mat.texture_slots.add()
tex_slot.texture = tex
tex_slot.texture_coords = 'UV'
tex_slot.uv_layer = uv.name
tex_slot.use_map_alpha = True
if self.style == 'BLEND':
if obj == to_obj:
tex_slot.alpha_factor = -1.0
elem = tex.color_ramp.elements[1]
else:
elem = tex.color_ramp.elements[0]
# Keep already defined alpha!
elem.color[:3] = mat.diffuse_color
else:
tex_slot.use_map_color_diffuse = False
if self.style == 'BLEND':
settings.physics_type = 'KEYED'
settings.use_emit_random = False
settings.rotation_mode = 'NOR'
psys = obj.particle_systems[-1]
fake_context["particle_system"] = obj.particle_systems[-1]
bpy.ops.particle.new_target(fake_context)
bpy.ops.particle.new_target(fake_context)
if obj == from_obj:
psys.targets[1].object = to_obj
else:
psys.targets[0].object = from_obj
settings.normal_factor = -self.velocity
explode.show_unborn = False
explode.show_dead = True
else:
settings.factor_random = self.velocity
settings.angular_velocity_factor = self.velocity / 10.0
return {'FINISHED'}
def invoke(self, context, event):
self.frame_start = context.scene.frame_current
self.frame_end = self.frame_start + self.frame_duration
return self.execute(context)
def obj_bb_minmax(obj, min_co, max_co):
for i in range(0, 8):
bb_vec = obj.matrix_world * Vector(obj.bound_box[i])

View File

@@ -384,36 +384,6 @@ class AddPresetFluid(AddPresetBase, Operator):
preset_subdir = "fluid"
class AddPresetHairDynamics(AddPresetBase, Operator):
"""Add or remove a Hair Dynamics Preset"""
bl_idname = "particle.hair_dynamics_preset_add"
bl_label = "Add Hair Dynamics Preset"
preset_menu = "PARTICLE_MT_hair_dynamics_presets"
preset_defines = [
"psys = bpy.context.particle_system",
"cloth = bpy.context.particle_system.cloth",
"settings = bpy.context.particle_system.cloth.settings",
"collision = bpy.context.particle_system.cloth.collision_settings",
]
preset_subdir = "hair_dynamics"
preset_values = [
"settings.quality",
"settings.mass",
"settings.bending_stiffness",
"psys.settings.bending_random",
"settings.bending_damping",
"settings.air_damping",
"settings.internal_friction",
"settings.density_target",
"settings.density_strength",
"settings.voxel_cell_size",
"settings.pin_stiffness",
]
class AddPresetSunSky(AddPresetBase, Operator):
"""Add or remove a Sky & Atmosphere Preset"""
bl_idname = "lamp.sunsky_preset_add"

View File

@@ -199,8 +199,6 @@ class VIEW3D_OT_select_or_deselect_all(Operator):
bpy.ops.armature.select_all(action='DESELECT')
elif active_object.mode == 'POSE':
bpy.ops.pose.select_all(action='DESELECT')
elif active_object.mode == 'PARTICLE_EDIT':
bpy.ops.particle.select_all(action='DESELECT')
else:
bpy.ops.object.select_all(action='DESELECT')
else:

View File

@@ -47,7 +47,6 @@ _modules = [
"properties_object",
"properties_paint_common",
"properties_grease_pencil_common",
"properties_particle",
"properties_physics_cloth",
"properties_physics_common",
"properties_physics_dynamicpaint",

View File

@@ -673,40 +673,6 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col = split.column()
def PARTICLE_INSTANCE(self, layout, ob, md):
layout.prop(md, "object")
layout.prop(md, "particle_system_index", text="Particle System")
split = layout.split()
col = split.column()
col.label(text="Create From:")
col.prop(md, "use_normal")
col.prop(md, "use_children")
col.prop(md, "use_size")
col = split.column()
col.label(text="Show Particles When:")
col.prop(md, "show_alive")
col.prop(md, "show_unborn")
col.prop(md, "show_dead")
layout.separator()
layout.prop(md, "use_path", text="Create Along Paths")
split = layout.split()
split.active = md.use_path
col = split.column()
col.row().prop(md, "axis", expand=True)
col.prop(md, "use_preserve_shape")
col = split.column()
col.prop(md, "position", slider=True)
col.prop(md, "random_position", text="Random", slider=True)
def PARTICLE_SYSTEM(self, layout, ob, md):
layout.label(text="Settings can be found inside the Particle context")
def SCREW(self, layout, ob, md):
split = layout.split()

View File

@@ -40,8 +40,6 @@ class UnifiedPaintPanel:
return toolsettings.image_paint
return None
elif context.particle_edit_object:
return toolsettings.particle_edit
return None

View File

@@ -1,1402 +0,0 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
import bpy
from bpy.types import Panel, Menu
from rna_prop_ui import PropertyPanel
from bpy.app.translations import pgettext_iface as iface_
from bl_ui.properties_physics_common import (
point_cache_ui,
effector_weights_ui,
basic_force_field_settings_ui,
basic_force_field_falloff_ui,
)
def particle_panel_enabled(context, psys):
if psys is None:
return True
phystype = psys.settings.physics_type
if psys.settings.type in {'EMITTER', 'REACTOR'} and phystype in {'NO', 'KEYED'}:
return True
else:
return (psys.point_cache.is_baked is False) and (not psys.is_edited) and (not context.particle_system_editable)
def particle_panel_poll(cls, context):
psys = context.particle_system
engine = context.scene.render.engine
settings = 0
if psys:
settings = psys.settings
elif isinstance(context.space_data.pin_id, bpy.types.ParticleSettings):
settings = context.space_data.pin_id
if not settings:
return False
return settings.is_fluid is False and (engine in cls.COMPAT_ENGINES)
def particle_get_settings(context):
if context.particle_system:
return context.particle_system.settings
elif isinstance(context.space_data.pin_id, bpy.types.ParticleSettings):
return context.space_data.pin_id
return None
class PARTICLE_MT_specials(Menu):
bl_label = "Particle Specials"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
props = layout.operator("particle.copy_particle_systems", text="Copy Active to Selected Objects")
props.use_active = True
props.remove_target_particles = False
props = layout.operator("particle.copy_particle_systems", text="Copy All to Selected Objects")
props.use_active = False
props.remove_target_particles = True
class PARTICLE_MT_hair_dynamics_presets(Menu):
bl_label = "Hair Dynamics Presets"
preset_subdir = "hair_dynamics"
preset_operator = "script.execute_preset"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
draw = Menu.draw_preset
class ParticleButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "particle"
@classmethod
def poll(cls, context):
return particle_panel_poll(cls, context)
def find_modifier(ob, psys):
for md in ob.modifiers:
if md.type == 'PARTICLE_SYSTEM':
if md.particle_system == psys:
return md
class PARTICLE_UL_particle_systems(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index, flt_flag):
ob = data
psys = item
if self.layout_type in {'DEFAULT', 'COMPACT'}:
md = find_modifier(ob, psys)
layout.prop(psys, "name", text="", emboss=False, icon_value=icon)
if md:
layout.prop(md, "show_render", emboss=False, icon_only=True, icon='RESTRICT_RENDER_OFF' if md.show_render else 'RESTRICT_RENDER_ON')
layout.prop(md, "show_viewport", emboss=False, icon_only=True, icon='RESTRICT_VIEW_OFF' if md.show_viewport else 'RESTRICT_VIEW_ON')
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
@classmethod
def poll(cls, context):
engine = context.scene.render.engine
return (context.particle_system or context.object or context.space_data.pin_id) and (engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
if context.scene.render.engine == 'BLENDER_GAME':
layout.label("Not available in the Game Engine")
return
ob = context.object
psys = context.particle_system
part = 0
if ob:
row = layout.row()
row.template_list("PARTICLE_UL_particle_systems", "particle_systems", ob, "particle_systems",
ob.particle_systems, "active_index", rows=1)
col = row.column(align=True)
col.operator("object.particle_system_add", icon='ZOOMIN', text="")
col.operator("object.particle_system_remove", icon='ZOOMOUT', text="")
col.menu("PARTICLE_MT_specials", icon='DOWNARROW_HLT', text="")
if psys is None:
part = particle_get_settings(context)
layout.operator("object.particle_system_add", icon='ZOOMIN', text="New")
if part is None:
return
layout.template_ID(context.space_data, "pin_id")
if part.is_fluid:
layout.label(text="Settings used for fluid")
return
layout.prop(part, "type", text="Type")
elif not psys.settings:
split = layout.split(percentage=0.32)
col = split.column()
col.label(text="Settings:")
col = split.column()
col.template_ID(psys, "settings", new="particle.new")
else:
part = psys.settings
split = layout.split(percentage=0.32)
col = split.column()
if part.is_fluid is False:
col.label(text="Settings:")
col.label(text="Type:")
col = split.column()
if part.is_fluid is False:
row = col.row()
row.enabled = particle_panel_enabled(context, psys)
row.template_ID(psys, "settings", new="particle.new")
if part.is_fluid:
layout.label(text=iface_("%d fluid particles for this frame") % part.count, translate=False)
return
row = col.row()
row.enabled = particle_panel_enabled(context, psys)
row.prop(part, "type", text="")
row.prop(psys, "seed")
if part:
split = layout.split(percentage=0.65)
if part.type == 'HAIR':
if psys is not None and psys.is_edited:
split.operator("particle.edited_clear", text="Free Edit")
else:
row = split.row()
row.enabled = particle_panel_enabled(context, psys)
row.prop(part, "regrow_hair")
row.prop(part, "use_advanced_hair")
row = split.row()
row.enabled = particle_panel_enabled(context, psys)
row.prop(part, "hair_step")
if psys is not None and psys.is_edited:
if psys.is_global_hair:
row = layout.row(align=True)
row.operator("particle.connect_hair").all = False
row.operator("particle.connect_hair", text="Connect All").all = True
else:
row = layout.row(align=True)
row.operator("particle.disconnect_hair").all = False
row.operator("particle.disconnect_hair", text="Disconnect All").all = True
elif psys is not None and part.type == 'REACTOR':
split.enabled = particle_panel_enabled(context, psys)
split.prop(psys, "reactor_target_object")
split.prop(psys, "reactor_target_particle_system", text="Particle System")
class PARTICLE_PT_emission(ParticleButtonsPanel, Panel):
bl_label = "Emission"
COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
psys = context.particle_system
settings = particle_get_settings(context)
if settings is None:
return False
if settings.is_fluid:
return False
if particle_panel_poll(PARTICLE_PT_emission, context):
return psys is None or not context.particle_system.point_cache.use_external
return False
def draw(self, context):
layout = self.layout
psys = context.particle_system
part = particle_get_settings(context)
layout.enabled = particle_panel_enabled(context, psys) and (psys is None or not psys.has_multiple_caches)
row = layout.row()
row.active = part.emit_from == 'VERT' or part.distribution != 'GRID'
row.prop(part, "count")
if part.type == 'HAIR':
row.prop(part, "hair_length")
if not part.use_advanced_hair:
row = layout.row()
row.prop(part, "use_modifier_stack")
return
if part.type != 'HAIR':
split = layout.split()
col = split.column(align=True)
col.prop(part, "frame_start")
col.prop(part, "frame_end")
col = split.column(align=True)
col.prop(part, "lifetime")
col.prop(part, "lifetime_random", slider=True)
layout.label(text="Emit From:")
layout.prop(part, "emit_from", expand=True)
row = layout.row()
if part.emit_from == 'VERT':
row.prop(part, "use_emit_random")
elif part.distribution == 'GRID':
row.prop(part, "invert_grid")
row.prop(part, "hexagonal_grid")
else:
row.prop(part, "use_emit_random")
row.prop(part, "use_even_distribution")
if part.emit_from == 'FACE' or part.emit_from == 'VOLUME':
layout.prop(part, "distribution", expand=True)
row = layout.row()
if part.distribution == 'JIT':
row.prop(part, "userjit", text="Particles/Face")
row.prop(part, "jitter_factor", text="Jittering Amount", slider=True)
elif part.distribution == 'GRID':
row.prop(part, "grid_resolution")
row.prop(part, "grid_random", text="Random", slider=True)
row = layout.row()
row.prop(part, "use_modifier_stack")
class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, Panel):
bl_label = "Hair dynamics"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
psys = context.particle_system
engine = context.scene.render.engine
if psys is None:
return False
if psys.settings is None:
return False
return psys.settings.type == 'HAIR' and (engine in cls.COMPAT_ENGINES)
def draw_header(self, context):
psys = context.particle_system
self.layout.prop(psys, "use_hair_dynamics", text="")
def draw(self, context):
layout = self.layout
psys = context.particle_system
if not psys.cloth:
return
cloth_md = psys.cloth
cloth = cloth_md.settings
result = cloth_md.solver_result
layout.enabled = psys.use_hair_dynamics and psys.point_cache.is_baked is False
row = layout.row(align=True)
row.menu("PARTICLE_MT_hair_dynamics_presets", text=bpy.types.PARTICLE_MT_hair_dynamics_presets.bl_label)
row.operator("particle.hair_dynamics_preset_add", text="", icon='ZOOMIN')
row.operator("particle.hair_dynamics_preset_add", text="", icon='ZOOMOUT').remove_active = True
split = layout.column()
col = split.column()
col.label(text="Structure")
col.prop(cloth, "mass")
sub = col.column(align=True)
subsub = sub.row(align=True)
subsub.prop(cloth, "bending_stiffness", text="Stiffness")
subsub.prop(psys.settings, "bending_random", text="Random")
sub.prop(cloth, "bending_damping", text="Damping")
# XXX has no noticeable effect with stiff hair structure springs
#col.prop(cloth, "spring_damping", text="Damping")
split.separator()
col = split.column()
col.label(text="Volume")
col.prop(cloth, "air_damping", text="Air Drag")
col.prop(cloth, "internal_friction", slider=True)
sub = col.column(align=True)
sub.prop(cloth, "density_target", text="Density Target")
sub.prop(cloth, "density_strength", slider=True, text="Strength")
col.prop(cloth, "voxel_cell_size")
split.separator()
col = split.column()
col.label(text="Pinning")
col.prop(cloth, "pin_stiffness", text="Goal Strength")
split.separator()
col = split.column()
col.label(text="Quality:")
col.prop(cloth, "quality", text="Steps", slider=True)
row = col.row()
row.prop(psys.settings, "show_hair_grid", text="HairGrid")
if result:
box = layout.box()
if not result.status:
label = " "
icon = 'NONE'
elif result.status == {'SUCCESS'}:
label = "Success"
icon = 'NONE'
elif result.status - {'SUCCESS'} == {'NO_CONVERGENCE'}:
label = "No Convergence"
icon = 'ERROR'
else:
label = "ERROR"
icon = 'ERROR'
box.label(label, icon=icon)
box.label("Iterations: %d .. %d (avg. %d)" % (result.min_iterations, result.max_iterations, result.avg_iterations))
box.label("Error: %.5f .. %.5f (avg. %.5f)" % (result.min_error, result.max_error, result.avg_error))
class PARTICLE_PT_cache(ParticleButtonsPanel, Panel):
bl_label = "Cache"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
psys = context.particle_system
engine = context.scene.render.engine
if psys is None:
return False
if psys.settings is None:
return False
if psys.settings.is_fluid:
return False
phystype = psys.settings.physics_type
if phystype == 'NO' or phystype == 'KEYED':
return False
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
def draw(self, context):
psys = context.particle_system
point_cache_ui(self, context, psys.point_cache, True, 'HAIR' if (psys.settings.type == 'HAIR') else 'PSYS')
class PARTICLE_PT_velocity(ParticleButtonsPanel, Panel):
bl_label = "Velocity"
COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
if particle_panel_poll(PARTICLE_PT_velocity, context):
psys = context.particle_system
settings = particle_get_settings(context)
if settings.type == 'HAIR' and not settings.use_advanced_hair:
return False
return settings.physics_type != 'BOIDS' and (psys is None or not psys.point_cache.use_external)
else:
return False
def draw(self, context):
layout = self.layout
psys = context.particle_system
part = particle_get_settings(context)
layout.enabled = particle_panel_enabled(context, psys)
split = layout.split()
col = split.column()
col.label(text="Emitter Geometry:")
col.prop(part, "normal_factor")
sub = col.column(align=True)
sub.prop(part, "tangent_factor")
sub.prop(part, "tangent_phase", slider=True)
col = split.column()
col.label(text="Emitter Object:")
col.prop(part, "object_align_factor", text="")
layout.label(text="Other:")
row = layout.row()
if part.emit_from == 'PARTICLE':
row.prop(part, "particle_factor")
else:
row.prop(part, "object_factor", slider=True)
row.prop(part, "factor_random")
#if part.type=='REACTOR':
# sub.prop(part, "reactor_factor")
# sub.prop(part, "reaction_shape", slider=True)
class PARTICLE_PT_rotation(ParticleButtonsPanel, Panel):
bl_label = "Rotation"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
if particle_panel_poll(PARTICLE_PT_rotation, context):
psys = context.particle_system
settings = particle_get_settings(context)
if settings.type == 'HAIR' and not settings.use_advanced_hair:
return False
return settings.physics_type != 'BOIDS' and (psys is None or not psys.point_cache.use_external)
else:
return False
def draw_header(self, context):
psys = context.particle_system
if psys:
part = psys.settings
else:
part = context.space_data.pin_id
self.layout.prop(part, "use_rotations", text="")
def draw(self, context):
layout = self.layout
psys = context.particle_system
if psys:
part = psys.settings
else:
part = context.space_data.pin_id
layout.enabled = particle_panel_enabled(context, psys) and part.use_rotations
layout.label(text="Initial Orientation:")
split = layout.split()
col = split.column(align=True)
col.prop(part, "rotation_mode", text="")
col.prop(part, "rotation_factor_random", slider=True, text="Random")
col = split.column(align=True)
col.prop(part, "phase_factor", slider=True)
col.prop(part, "phase_factor_random", text="Random", slider=True)
if part.type != 'HAIR':
layout.label(text="Angular Velocity:")
split = layout.split()
col = split.column(align=True)
col.prop(part, "angular_velocity_mode", text="")
sub = col.column(align=True)
sub.active = part.angular_velocity_mode != 'NONE'
sub.prop(part, "angular_velocity_factor", text="")
col = split.column()
col.prop(part, "use_dynamic_rotation")
class PARTICLE_PT_physics(ParticleButtonsPanel, Panel):
bl_label = "Physics"
COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
if particle_panel_poll(PARTICLE_PT_physics, context):
psys = context.particle_system
settings = particle_get_settings(context)
if settings.type == 'HAIR' and not settings.use_advanced_hair:
return False
return psys is None or not psys.point_cache.use_external
else:
return False
def draw(self, context):
layout = self.layout
psys = context.particle_system
part = particle_get_settings(context)
layout.enabled = particle_panel_enabled(context, psys)
layout.prop(part, "physics_type", expand=True)
row = layout.row()
col = row.column(align=True)
col.prop(part, "particle_size")
col.prop(part, "size_random", slider=True)
if part.physics_type != 'NO':
col = row.column(align=True)
col.prop(part, "mass")
col.prop(part, "use_multiply_size_mass", text="Multiply mass with size")
if part.physics_type in {'NEWTON', 'FLUID'}:
split = layout.split()
col = split.column()
col.label(text="Forces:")
col.prop(part, "brownian_factor")
col.prop(part, "drag_factor", slider=True)
col.prop(part, "damping", slider=True)
col = split.column()
col.label(text="Integration:")
col.prop(part, "integrator", text="")
col.prop(part, "timestep")
sub = col.row()
sub.prop(part, "subframes")
supports_courant = part.physics_type == 'FLUID'
subsub = sub.row()
subsub.enabled = supports_courant
subsub.prop(part, "use_adaptive_subframes", text="")
if supports_courant and part.use_adaptive_subframes:
col.prop(part, "courant_target", text="Threshold")
row = layout.row()
row.prop(part, "use_size_deflect")
row.prop(part, "use_die_on_collision")
if part.physics_type == 'FLUID':
fluid = part.fluid
split = layout.split()
sub = split.row()
sub.prop(fluid, "solver", expand=True)
split = layout.split()
col = split.column()
col.label(text="Fluid properties:")
col.prop(fluid, "stiffness", text="Stiffness")
col.prop(fluid, "linear_viscosity", text="Viscosity")
col.prop(fluid, "buoyancy", text="Buoyancy", slider=True)
col = split.column()
col.label(text="Advanced:")
if fluid.solver == 'DDR':
sub = col.row()
sub.prop(fluid, "repulsion", slider=fluid.factor_repulsion)
sub.prop(fluid, "factor_repulsion", text="")
sub = col.row()
sub.prop(fluid, "stiff_viscosity", slider=fluid.factor_stiff_viscosity)
sub.prop(fluid, "factor_stiff_viscosity", text="")
sub = col.row()
sub.prop(fluid, "fluid_radius", slider=fluid.factor_radius)
sub.prop(fluid, "factor_radius", text="")
sub = col.row()
sub.prop(fluid, "rest_density", slider=fluid.use_factor_density)
sub.prop(fluid, "use_factor_density", text="")
if fluid.solver == 'CLASSICAL':
# With the classical solver, it is possible to calculate the
# spacing between particles when the fluid is at rest. This
# makes it easier to set stable initial conditions.
particle_volume = part.mass / fluid.rest_density
spacing = pow(particle_volume, 1.0 / 3.0)
sub = col.row()
sub.label(text="Spacing: %g" % spacing)
elif fluid.solver == 'DDR':
split = layout.split()
col = split.column()
col.label(text="Springs:")
col.prop(fluid, "spring_force", text="Force")
col.prop(fluid, "use_viscoelastic_springs")
sub = col.column(align=True)
sub.active = fluid.use_viscoelastic_springs
sub.prop(fluid, "yield_ratio", slider=True)
sub.prop(fluid, "plasticity", slider=True)
col = split.column()
col.label(text="Advanced:")
sub = col.row()
sub.prop(fluid, "rest_length", slider=fluid.factor_rest_length)
sub.prop(fluid, "factor_rest_length", text="")
col.label(text="")
sub = col.column()
sub.active = fluid.use_viscoelastic_springs
sub.prop(fluid, "use_initial_rest_length")
sub.prop(fluid, "spring_frames", text="Frames")
elif part.physics_type == 'KEYED':
split = layout.split()
sub = split.column()
row = layout.row()
col = row.column()
col.active = not psys.use_keyed_timing
col.prop(part, "keyed_loops", text="Loops")
if psys:
row.prop(psys, "use_keyed_timing", text="Use Timing")
layout.label(text="Keys:")
elif part.physics_type == 'BOIDS':
boids = part.boids
row = layout.row()
row.prop(boids, "use_flight")
row.prop(boids, "use_land")
row.prop(boids, "use_climb")
split = layout.split()
col = split.column(align=True)
col.active = boids.use_flight
col.prop(boids, "air_speed_max")
col.prop(boids, "air_speed_min", slider=True)
col.prop(boids, "air_acc_max", slider=True)
col.prop(boids, "air_ave_max", slider=True)
col.prop(boids, "air_personal_space")
row = col.row(align=True)
row.active = (boids.use_land or boids.use_climb) and boids.use_flight
row.prop(boids, "land_smooth")
col = split.column(align=True)
col.active = boids.use_land or boids.use_climb
col.prop(boids, "land_speed_max")
col.prop(boids, "land_jump_speed")
col.prop(boids, "land_acc_max", slider=True)
col.prop(boids, "land_ave_max", slider=True)
col.prop(boids, "land_personal_space")
col.prop(boids, "land_stick_force")
split = layout.split()
col = split.column(align=True)
col.label(text="Battle:")
col.prop(boids, "health")
col.prop(boids, "strength")
col.prop(boids, "aggression")
col.prop(boids, "accuracy")
col.prop(boids, "range")
col = split.column()
col.label(text="Misc:")
col.prop(boids, "bank", slider=True)
col.prop(boids, "pitch", slider=True)
col.prop(boids, "height", slider=True)
if psys and part.physics_type in {'KEYED', 'BOIDS', 'FLUID'}:
if part.physics_type == 'BOIDS':
layout.label(text="Relations:")
elif part.physics_type == 'FLUID':
layout.label(text="Fluid interaction:")
row = layout.row()
row.template_list("UI_UL_list", "particle_targets", psys, "targets", psys, "active_particle_target_index", rows=4)
col = row.column()
sub = col.row()
subsub = sub.column(align=True)
subsub.operator("particle.new_target", icon='ZOOMIN', text="")
subsub.operator("particle.target_remove", icon='ZOOMOUT', text="")
sub = col.row()
subsub = sub.column(align=True)
subsub.operator("particle.target_move_up", icon='MOVE_UP_VEC', text="")
subsub.operator("particle.target_move_down", icon='MOVE_DOWN_VEC', text="")
key = psys.active_particle_target
if key:
row = layout.row()
if part.physics_type == 'KEYED':
col = row.column()
#doesn't work yet
#col.alert = key.valid
col.prop(key, "object", text="")
col.prop(key, "system", text="System")
col = row.column()
col.active = psys.use_keyed_timing
col.prop(key, "time")
col.prop(key, "duration")
elif part.physics_type == 'BOIDS':
sub = row.row()
#doesn't work yet
#sub.alert = key.valid
sub.prop(key, "object", text="")
sub.prop(key, "system", text="System")
layout.prop(key, "alliance", expand=True)
elif part.physics_type == 'FLUID':
sub = row.row()
#doesn't work yet
#sub.alert = key.valid
sub.prop(key, "object", text="")
sub.prop(key, "system", text="System")
class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel):
bl_label = "Boid Brain"
COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
psys = context.particle_system
settings = particle_get_settings(context)
engine = context.scene.render.engine
if settings is None:
return False
if psys is not None and psys.point_cache.use_external:
return False
return settings.physics_type == 'BOIDS' and engine in cls.COMPAT_ENGINES
def draw(self, context):
layout = self.layout
boids = particle_get_settings(context).boids
layout.enabled = particle_panel_enabled(context, context.particle_system)
# Currently boids can only use the first state so these are commented out for now.
#row = layout.row()
#row.template_list("UI_UL_list", "particle_boids", boids, "states",
# boids, "active_boid_state_index", compact="True")
#col = row.row()
#sub = col.row(align=True)
#sub.operator("boid.state_add", icon='ZOOMIN', text="")
#sub.operator("boid.state_del", icon='ZOOMOUT', text="")
#sub = row.row(align=True)
#sub.operator("boid.state_move_up", icon='MOVE_UP_VEC', text="")
#sub.operator("boid.state_move_down", icon='MOVE_DOWN_VEC', text="")
state = boids.active_boid_state
#layout.prop(state, "name", text="State name")
row = layout.row()
row.prop(state, "ruleset_type")
if state.ruleset_type == 'FUZZY':
row.prop(state, "rule_fuzzy", slider=True)
else:
row.label(text="")
row = layout.row()
row.template_list("UI_UL_list", "particle_boids_rules", state, "rules", state, "active_boid_rule_index", rows=4)
col = row.column()
sub = col.row()
subsub = sub.column(align=True)
subsub.operator_menu_enum("boid.rule_add", "type", icon='ZOOMIN', text="")
subsub.operator("boid.rule_del", icon='ZOOMOUT', text="")
sub = col.row()
subsub = sub.column(align=True)
subsub.operator("boid.rule_move_up", icon='MOVE_UP_VEC', text="")
subsub.operator("boid.rule_move_down", icon='MOVE_DOWN_VEC', text="")
rule = state.active_boid_rule
if rule:
row = layout.row()
row.prop(rule, "name", text="")
#somebody make nice icons for boids here please! -jahka
row.prop(rule, "use_in_air", icon='MOVE_UP_VEC', text="")
row.prop(rule, "use_on_land", icon='MOVE_DOWN_VEC', text="")
row = layout.row()
if rule.type == 'GOAL':
row.prop(rule, "object")
row = layout.row()
row.prop(rule, "use_predict")
elif rule.type == 'AVOID':
row.prop(rule, "object")
row = layout.row()
row.prop(rule, "use_predict")
row.prop(rule, "fear_factor")
elif rule.type == 'FOLLOW_PATH':
row.label(text="Not yet functional")
elif rule.type == 'AVOID_COLLISION':
row.prop(rule, "use_avoid")
row.prop(rule, "use_avoid_collision")
row.prop(rule, "look_ahead")
elif rule.type == 'FOLLOW_LEADER':
row.prop(rule, "object", text="")
row.prop(rule, "distance")
row = layout.row()
row.prop(rule, "use_line")
sub = row.row()
sub.active = rule.line
sub.prop(rule, "queue_count")
elif rule.type == 'AVERAGE_SPEED':
row.prop(rule, "speed", slider=True)
row.prop(rule, "wander", slider=True)
row.prop(rule, "level", slider=True)
elif rule.type == 'FIGHT':
row.prop(rule, "distance")
row.prop(rule, "flee_distance")
class PARTICLE_PT_render(ParticleButtonsPanel, Panel):
bl_label = "Render"
COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
settings = particle_get_settings(context)
engine = context.scene.render.engine
if settings is None:
return False
return engine in cls.COMPAT_ENGINES
def draw(self, context):
layout = self.layout
psys = context.particle_system
part = particle_get_settings(context)
if psys:
row = layout.row()
if part.render_type in {'OBJECT', 'GROUP'}:
row.enabled = False
row.prop(part, "material_slot", text="")
row.prop(psys, "parent")
split = layout.split()
col = split.column()
col.prop(part, "use_render_emitter")
col.prop(part, "use_parent_particles")
col = split.column()
col.prop(part, "show_unborn")
col.prop(part, "use_dead")
layout.prop(part, "render_type", expand=True)
split = layout.split()
col = split.column()
if part.render_type == 'LINE':
col.prop(part, "line_length_tail")
col.prop(part, "line_length_head")
split.prop(part, "use_velocity_length")
elif part.render_type == 'PATH':
col.prop(part, "use_strand_primitive")
sub = col.column()
sub.active = (part.use_strand_primitive is False)
sub.prop(part, "use_render_adaptive")
sub = col.column()
sub.active = part.use_render_adaptive or part.use_strand_primitive is True
sub.prop(part, "adaptive_angle")
sub = col.column()
sub.active = (part.use_render_adaptive is True and part.use_strand_primitive is False)
sub.prop(part, "adaptive_pixel")
col.prop(part, "use_hair_bspline")
col.prop(part, "render_step", text="Steps")
col = split.column()
col.label(text="Timing:")
col.prop(part, "use_absolute_path_time")
if part.type == 'HAIR' or psys.point_cache.is_baked:
col.prop(part, "path_start", text="Start", slider=not part.use_absolute_path_time)
else:
col.prop(part, "trail_count")
col.prop(part, "path_end", text="End", slider=not part.use_absolute_path_time)
col.prop(part, "length_random", text="Random", slider=True)
row = layout.row()
col = row.column()
if part.type == 'HAIR' and part.use_strand_primitive is True and part.child_type == 'INTERPOLATED':
layout.prop(part, "use_simplify")
if part.use_simplify is True:
row = layout.row()
row.prop(part, "simplify_refsize")
row.prop(part, "simplify_rate")
row.prop(part, "simplify_transition")
row = layout.row()
row.prop(part, "use_simplify_viewport")
sub = row.row()
sub.active = part.use_simplify_viewport is True
sub.prop(part, "simplify_viewport")
elif part.render_type == 'OBJECT':
col.prop(part, "dupli_object")
sub = col.row()
sub.prop(part, "use_global_dupli")
sub.prop(part, "use_rotation_dupli")
sub.prop(part, "use_scale_dupli")
elif part.render_type == 'GROUP':
col.prop(part, "dupli_group")
split = layout.split()
col = split.column()
col.prop(part, "use_whole_group")
sub = col.column()
sub.active = (part.use_whole_group is False)
sub.prop(part, "use_group_pick_random")
sub.prop(part, "use_group_count")
col = split.column()
sub = col.column()
sub.active = (part.use_whole_group is False)
sub.prop(part, "use_global_dupli")
sub.prop(part, "use_rotation_dupli")
sub.prop(part, "use_scale_dupli")
if part.use_group_count and not part.use_whole_group:
row = layout.row()
row.template_list("UI_UL_list", "particle_dupli_weights", part, "dupli_weights",
part, "active_dupliweight_index")
col = row.column()
sub = col.row()
subsub = sub.column(align=True)
subsub.operator("particle.dupliob_copy", icon='ZOOMIN', text="")
subsub.operator("particle.dupliob_remove", icon='ZOOMOUT', text="")
subsub.operator("particle.dupliob_move_up", icon='MOVE_UP_VEC', text="")
subsub.operator("particle.dupliob_move_down", icon='MOVE_DOWN_VEC', text="")
weight = part.active_dupliweight
if weight:
row = layout.row()
row.prop(weight, "count")
elif part.render_type == 'BILLBOARD':
ob = context.object
col.label(text="Align:")
row = layout.row()
row.prop(part, "billboard_align", expand=True)
row.prop(part, "lock_billboard", text="Lock")
row = layout.row()
row.prop(part, "billboard_object")
row = layout.row()
col = row.column(align=True)
col.label(text="Tilt:")
col.prop(part, "billboard_tilt", text="Angle", slider=True)
col.prop(part, "billboard_tilt_random", text="Random", slider=True)
col = row.column()
col.prop(part, "billboard_offset")
row = layout.row()
col = row.column()
col.prop(part, "billboard_size", text="Scale")
if part.billboard_align == 'VEL':
col = row.column(align=True)
col.label("Velocity Scale:")
col.prop(part, "billboard_velocity_head", text="Head")
col.prop(part, "billboard_velocity_tail", text="Tail")
if psys:
col = layout.column()
col.prop_search(psys, "billboard_normal_uv", ob.data, "uv_textures")
col.prop_search(psys, "billboard_time_index_uv", ob.data, "uv_textures")
split = layout.split(percentage=0.33)
split.label(text="Split UVs:")
split.prop(part, "billboard_uv_split", text="Number of splits")
if psys:
col = layout.column()
col.active = part.billboard_uv_split > 1
col.prop_search(psys, "billboard_split_uv", ob.data, "uv_textures")
row = col.row()
row.label(text="Animate:")
row.prop(part, "billboard_animation", text="")
row.label(text="Offset:")
row.prop(part, "billboard_offset_split", text="")
if part.render_type == 'HALO' or part.render_type == 'LINE' or part.render_type == 'BILLBOARD':
row = layout.row()
col = row.column()
col.prop(part, "trail_count")
if part.trail_count > 1:
col.prop(part, "use_absolute_path_time", text="Length in frames")
col = row.column()
col.prop(part, "path_end", text="Length", slider=not part.use_absolute_path_time)
col.prop(part, "length_random", text="Random", slider=True)
else:
col = row.column()
col.label(text="")
if part.render_type in {'OBJECT', 'GROUP'} and not part.use_advanced_hair:
row = layout.row(align=True)
row.prop(part, "particle_size")
row.prop(part, "size_random", slider=True)
class PARTICLE_PT_draw(ParticleButtonsPanel, Panel):
bl_label = "Display"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
settings = particle_get_settings(context)
engine = context.scene.render.engine
if settings is None:
return False
return engine in cls.COMPAT_ENGINES
def draw(self, context):
layout = self.layout
psys = context.particle_system
part = particle_get_settings(context)
row = layout.row()
row.prop(part, "draw_method", expand=True)
row.prop(part, "show_guide_hairs")
if part.draw_method == 'NONE' or (part.render_type == 'NONE' and part.draw_method == 'RENDER'):
return
path = (part.render_type == 'PATH' and part.draw_method == 'RENDER') or part.draw_method == 'PATH'
row = layout.row()
row.prop(part, "draw_percentage", slider=True)
if part.draw_method != 'RENDER' or part.render_type == 'HALO':
row.prop(part, "draw_size")
else:
row.label(text="")
if part.draw_percentage != 100 and psys is not None:
if part.type == 'HAIR':
if psys.use_hair_dynamics and psys.point_cache.is_baked is False:
layout.row().label(text="Display percentage makes dynamics inaccurate without baking!")
else:
phystype = part.physics_type
if phystype != 'NO' and phystype != 'KEYED' and psys.point_cache.is_baked is False:
layout.row().label(text="Display percentage makes dynamics inaccurate without baking!")
row = layout.row()
col = row.column()
col.prop(part, "show_size")
col.prop(part, "show_velocity")
col.prop(part, "show_number")
if part.physics_type == 'BOIDS':
col.prop(part, "show_health")
col = row.column(align=True)
col.label(text="Color:")
col.prop(part, "draw_color", text="")
sub = col.row(align=True)
sub.active = (part.draw_color in {'VELOCITY', 'ACCELERATION'})
sub.prop(part, "color_maximum", text="Max")
if path:
col.prop(part, "draw_step")
class PARTICLE_PT_children(ParticleButtonsPanel, Panel):
bl_label = "Children"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
return particle_panel_poll(cls, context)
def draw(self, context):
layout = self.layout
psys = context.particle_system
part = particle_get_settings(context)
layout.row().prop(part, "child_type", expand=True)
if part.child_type == 'NONE':
return
row = layout.row()
col = row.column(align=True)
col.prop(part, "child_nbr", text="Display")
col.prop(part, "rendered_child_count", text="Render")
if part.child_type == 'INTERPOLATED':
col = row.column()
if psys:
col.prop(psys, "child_seed", text="Seed")
col.prop(part, "virtual_parents", slider=True)
col.prop(part, "create_long_hair_children")
else:
col = row.column(align=True)
col.prop(part, "child_size", text="Size")
col.prop(part, "child_size_random", text="Random")
split = layout.split()
col = split.column()
col.label(text="Effects:")
sub = col.column(align=True)
sub.prop(part, "use_clump_curve")
if part.use_clump_curve:
sub.template_curve_mapping(part, "clump_curve")
else:
sub.prop(part, "clump_factor", slider=True)
sub.prop(part, "clump_shape", slider=True)
sub = col.column(align=True)
sub.prop(part, "use_clump_noise")
subsub = sub.column()
subsub.enabled = part.use_clump_noise
subsub.prop(part, "clump_noise_size")
sub = col.column(align=True)
sub.prop(part, "child_length", slider=True)
sub.prop(part, "child_length_threshold", slider=True)
if part.child_type == 'SIMPLE':
sub = col.column(align=True)
sub.prop(part, "child_radius", text="Radius")
sub.prop(part, "child_roundness", text="Roundness", slider=True)
if psys:
sub.prop(psys, "child_seed", text="Seed")
elif part.virtual_parents > 0.0:
sub = col.column(align=True)
sub.label(text="Parting not")
sub.label(text="available with")
sub.label(text="virtual parents")
else:
sub = col.column(align=True)
sub.prop(part, "child_parting_factor", text="Parting", slider=True)
sub.prop(part, "child_parting_min", text="Min")
sub.prop(part, "child_parting_max", text="Max")
col = split.column()
col.prop(part, "use_roughness_curve")
if part.use_roughness_curve:
sub = col.column()
sub.template_curve_mapping(part, "roughness_curve")
sub.prop(part, "roughness_1", text="Roughness")
sub.prop(part, "roughness_1_size", text="Size")
else:
col.label(text="Roughness:")
sub = col.column(align=True)
sub.prop(part, "roughness_1", text="Uniform")
sub.prop(part, "roughness_1_size", text="Size")
sub = col.column(align=True)
sub.prop(part, "roughness_endpoint", "Endpoint")
sub.prop(part, "roughness_end_shape")
sub = col.column(align=True)
sub.prop(part, "roughness_2", text="Random")
sub.prop(part, "roughness_2_size", text="Size")
sub.prop(part, "roughness_2_threshold", slider=True)
layout.row().label(text="Kink:")
layout.row().prop(part, "kink", expand=True)
split = layout.split()
split.active = part.kink != 'NO'
if part.kink == 'SPIRAL':
col = split.column()
sub = col.column(align=True)
sub.prop(part, "kink_amplitude", text="Radius")
sub.prop(part, "kink_amplitude_random", text="Random", slider=True)
sub = col.column(align=True)
sub.prop(part, "kink_axis")
sub.prop(part, "kink_axis_random", text="Random", slider=True)
col = split.column(align=True)
col.prop(part, "kink_frequency", text="Frequency")
col.prop(part, "kink_shape", text="Shape", slider=True)
col.prop(part, "kink_extra_steps", text="Steps")
else:
col = split.column()
sub = col.column(align=True)
sub.prop(part, "kink_amplitude")
sub.prop(part, "kink_amplitude_clump", text="Clump", slider=True)
col.prop(part, "kink_flat", slider=True)
col = split.column(align=True)
col.prop(part, "kink_frequency")
col.prop(part, "kink_shape", slider=True)
class PARTICLE_PT_field_weights(ParticleButtonsPanel, Panel):
bl_label = "Field Weights"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
return particle_panel_poll(cls, context)
def draw(self, context):
part = particle_get_settings(context)
effector_weights_ui(self, context, part.effector_weights, 'PSYS')
if part.type == 'HAIR':
row = self.layout.row()
row.prop(part.effector_weights, "apply_to_hair_growing")
row.prop(part, "apply_effector_to_children")
row = self.layout.row()
row.prop(part, "effect_hair", slider=True)
class PARTICLE_PT_force_fields(ParticleButtonsPanel, Panel):
bl_label = "Force Field Settings"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
part = particle_get_settings(context)
row = layout.row()
row.prop(part, "use_self_effect")
row.prop(part, "effector_amount", text="Amount")
split = layout.split(percentage=0.2)
split.label(text="Type 1:")
split.prop(part.force_field_1, "type", text="")
basic_force_field_settings_ui(self, context, part.force_field_1)
if part.force_field_1.type != 'NONE':
layout.label(text="Falloff:")
basic_force_field_falloff_ui(self, context, part.force_field_1)
if part.force_field_1.type != 'NONE':
layout.label(text="")
split = layout.split(percentage=0.2)
split.label(text="Type 2:")
split.prop(part.force_field_2, "type", text="")
basic_force_field_settings_ui(self, context, part.force_field_2)
if part.force_field_2.type != 'NONE':
layout.label(text="Falloff:")
basic_force_field_falloff_ui(self, context, part.force_field_2)
class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, Panel):
bl_label = "Vertex Groups"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
if context.particle_system is None:
return False
return particle_panel_poll(cls, context)
def draw(self, context):
layout = self.layout
ob = context.object
psys = context.particle_system
col = layout.column()
row = col.row(align=True)
row.prop_search(psys, "vertex_group_density", ob, "vertex_groups", text="Density")
row.prop(psys, "invert_vertex_group_density", text="", toggle=True, icon='ARROW_LEFTRIGHT')
row = col.row(align=True)
row.prop_search(psys, "vertex_group_length", ob, "vertex_groups", text="Length")
row.prop(psys, "invert_vertex_group_length", text="", toggle=True, icon='ARROW_LEFTRIGHT')
row = col.row(align=True)
row.prop_search(psys, "vertex_group_clump", ob, "vertex_groups", text="Clump")
row.prop(psys, "invert_vertex_group_clump", text="", toggle=True, icon='ARROW_LEFTRIGHT')
row = col.row(align=True)
row.prop_search(psys, "vertex_group_kink", ob, "vertex_groups", text="Kink")
row.prop(psys, "invert_vertex_group_kink", text="", toggle=True, icon='ARROW_LEFTRIGHT')
row = col.row(align=True)
row.prop_search(psys, "vertex_group_roughness_1", ob, "vertex_groups", text="Roughness 1")
row.prop(psys, "invert_vertex_group_roughness_1", text="", toggle=True, icon='ARROW_LEFTRIGHT')
row = col.row(align=True)
row.prop_search(psys, "vertex_group_roughness_2", ob, "vertex_groups", text="Roughness 2")
row.prop(psys, "invert_vertex_group_roughness_2", text="", toggle=True, icon='ARROW_LEFTRIGHT')
row = col.row(align=True)
row.prop_search(psys, "vertex_group_roughness_end", ob, "vertex_groups", text="Roughness End")
row.prop(psys, "invert_vertex_group_roughness_end", text="", toggle=True, icon='ARROW_LEFTRIGHT')
# Commented out vertex groups don't work and are still waiting for better implementation
# row = layout.row()
# row.prop_search(psys, "vertex_group_velocity", ob, "vertex_groups", text="Velocity")
# row.prop(psys, "invert_vertex_group_velocity", text="")
# row = layout.row()
# row.prop_search(psys, "vertex_group_size", ob, "vertex_groups", text="Size")
# row.prop(psys, "invert_vertex_group_size", text="")
# row = layout.row()
# row.prop_search(psys, "vertex_group_tangent", ob, "vertex_groups", text="Tangent")
# row.prop(psys, "invert_vertex_group_tangent", text="")
# row = layout.row()
# row.prop_search(psys, "vertex_group_rotation", ob, "vertex_groups", text="Rotation")
# row.prop(psys, "invert_vertex_group_rotation", text="")
# row = layout.row()
# row.prop_search(psys, "vertex_group_field", ob, "vertex_groups", text="Field")
# row.prop(psys, "invert_vertex_group_field", text="")
class PARTICLE_PT_custom_props(ParticleButtonsPanel, PropertyPanel, Panel):
COMPAT_ENGINES = {'BLENDER_RENDER'}
_context_path = "particle_system.settings"
_property_type = bpy.types.ParticleSettings
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)

View File

@@ -97,7 +97,7 @@ class PHYSICS_PT_add(PhysicButtonsPanel, Panel):
'CONSTRAINT') # RB_TODO needs better icon
# cache-type can be 'PSYS' 'HAIR' 'SMOKE' etc
# cache-type can be 'CLOTH', 'SMOKE' etc
def point_cache_ui(self, context, cache, enabled, cachetype):
layout = self.layout
@@ -113,11 +113,9 @@ def point_cache_ui(self, context, cache, enabled, cachetype):
col.operator("ptcache.remove", icon='ZOOMOUT', text="")
row = layout.row()
if cachetype in {'PSYS', 'HAIR', 'SMOKE'}:
if cachetype == 'SMOKE':
row.prop(cache, "use_external")
if cachetype == 'SMOKE':
row.prop(cache, "use_library_path", "Use Lib Path")
row.prop(cache, "use_library_path", "Use Lib Path")
if cache.use_external:
split = layout.split(percentage=0.35)
@@ -141,7 +139,7 @@ def point_cache_ui(self, context, cache, enabled, cachetype):
if not cache.use_external or cachetype == 'SMOKE':
row = layout.row(align=True)
if cachetype not in {'PSYS', 'DYNAMIC_PAINT'}:
if cachetype != 'DYNAMIC_PAINT':
row.enabled = enabled
row.prop(cache, "frame_start")
row.prop(cache, "frame_end")

View File

@@ -124,10 +124,8 @@ class PHYSICS_PT_dynamic_paint(PhysicButtonsPanel, Panel):
col = split.column()
if not use_shading_nodes:
sub = col.column()
sub.active = (brush.paint_source != 'PARTICLE_SYSTEM')
sub.prop(brush, "use_material")
if brush.use_material and brush.paint_source != 'PARTICLE_SYSTEM' and not use_shading_nodes:
col.prop(brush, "use_material")
if brush.use_material and not use_shading_nodes:
col.prop(brush, "material", text="")
col.prop(brush, "paint_alpha", text="Alpha Factor")
else:
@@ -429,16 +427,6 @@ class PHYSICS_PT_dp_brush_source(PhysicButtonsPanel, Panel):
col = split.column()
col.prop(brush, "paint_source")
if brush.paint_source == 'PARTICLE_SYSTEM':
col.prop_search(brush, "particle_system", ob, "particle_systems", text="")
if brush.particle_system:
col.label(text="Particle effect:")
sub = col.column()
sub.active = not brush.use_particle_radius
sub.prop(brush, "solid_radius", text="Solid Radius")
col.prop(brush, "use_particle_radius", text="Use Particle's Radius")
col.prop(brush, "smooth_radius", text="Smooth radius")
if brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE', 'POINT'}:
col.prop(brush, "paint_distance", text="Paint Distance")
split = layout.row().split(percentage=0.4)

View File

@@ -86,14 +86,7 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
col = split.column()
col.label(text="Flow Source:")
col.prop(flow, "smoke_flow_source", expand=False, text="")
if flow.smoke_flow_source == 'PARTICLES':
col.label(text="Particle System:")
col.prop_search(flow, "particle_system", ob, "particle_systems", text="")
col.prop(flow, "use_particle_size", text="Set Size")
sub = col.column()
sub.active = flow.use_particle_size
sub.prop(flow, "particle_size")
else:
if flow.smoke_flow_source == 'MESH':
col.prop(flow, "surface_distance")
col.prop(flow, "volume_density")

View File

@@ -427,12 +427,10 @@ class SCENE_PT_simplify(SceneButtonsPanel, Panel):
col = split.column()
col.label(text="Viewport:")
col.prop(rd, "simplify_subdivision", text="Subdivision")
col.prop(rd, "simplify_child_particles", text="Child Particles")
col = split.column()
col.label(text="Render:")
col.prop(rd, "simplify_subdivision_render", text="Subdivision")
col.prop(rd, "simplify_child_particles_render", text="Child Particles")
col.prop(rd, "simplify_shadow_samples", text="Shadow Samples")
col.prop(rd, "simplify_ao_sss", text="AO and SSS")
col.prop(rd, "use_simplify_triangulate")

View File

@@ -26,7 +26,6 @@ from bpy.types import (
Lamp,
Material,
Object,
ParticleSettings,
Texture,
World,
)
@@ -101,9 +100,6 @@ def context_tex_datablock(context):
if idblock:
return idblock
if context.particle_system:
idblock = context.particle_system.settings
return idblock
@@ -142,8 +138,6 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel, Panel):
context.lamp or
context.texture or
context.line_style or
context.particle_system or
isinstance(context.space_data.pin_id, ParticleSettings) or
context.texture_user) and
(engine in cls.COMPAT_ENGINES))
@@ -811,18 +805,7 @@ class TEXTURE_PT_pointdensity(TextureButtonsPanel, Panel):
split = layout.split()
col = split.column()
if pd.point_source == 'PARTICLE_SYSTEM':
col.label(text="Object:")
col.prop(pd, "object", text="")
sub = col.column()
sub.enabled = bool(pd.object)
if pd.object:
sub.label(text="System:")
sub.prop_search(pd, "particle_system", pd.object, "particle_systems", text="")
sub.label(text="Cache:")
sub.prop(pd, "particle_cache_space", text="")
else:
if pd.point_source == 'OBJECT':
col.label(text="Object:")
col.prop(pd, "object", text="")
col.label(text="Cache:")
@@ -831,13 +814,7 @@ class TEXTURE_PT_pointdensity(TextureButtonsPanel, Panel):
col.separator()
col.label(text="Color Source:")
if pd.point_source == 'PARTICLE_SYSTEM':
col.prop(pd, "particle_color_source", text="")
if pd.particle_color_source in {'PARTICLE_SPEED', 'PARTICLE_VELOCITY'}:
col.prop(pd, "speed_scale")
if pd.particle_color_source in {'PARTICLE_SPEED', 'PARTICLE_AGE'}:
layout.template_color_ramp(pd, "color_ramp", expand=True)
else:
if pd.point_source == 'OBJECT':
col.prop(pd, "vertex_color_source", text="")
if pd.vertex_color_source == 'VERTEX_COLOR':
if pd.object and pd.object.data:
@@ -854,8 +831,6 @@ class TEXTURE_PT_pointdensity(TextureButtonsPanel, Panel):
col.prop(pd, "falloff", text="")
if pd.falloff == 'SOFT':
col.prop(pd, "falloff_soft")
if pd.falloff == 'PARTICLE_VELOCITY':
col.prop(pd, "falloff_speed_scale")
col.prop(pd, "use_falloff_curve")
@@ -1147,35 +1122,6 @@ class TEXTURE_PT_influence(TextureSlotPanel, Panel):
col = split.column()
factor_but(col, "use_map_zenith_up", "zenith_up_factor", "Zenith Up")
factor_but(col, "use_map_zenith_down", "zenith_down_factor", "Zenith Down")
elif isinstance(idblock, ParticleSettings):
split = layout.split()
col = split.column()
col.label(text="General:")
factor_but(col, "use_map_time", "time_factor", "Time")
factor_but(col, "use_map_life", "life_factor", "Lifetime")
factor_but(col, "use_map_density", "density_factor", "Density")
factor_but(col, "use_map_size", "size_factor", "Size")
col = split.column()
col.label(text="Physics:")
factor_but(col, "use_map_velocity", "velocity_factor", "Velocity")
factor_but(col, "use_map_damp", "damp_factor", "Damp")
factor_but(col, "use_map_gravity", "gravity_factor", "Gravity")
factor_but(col, "use_map_field", "field_factor", "Force Fields")
layout.label(text="Hair:")
split = layout.split()
col = split.column()
factor_but(col, "use_map_length", "length_factor", "Length")
factor_but(col, "use_map_clump", "clump_factor", "Clump")
col = split.column()
factor_but(col, "use_map_kink_amp", "kink_amp_factor", "Kink Amplitude")
factor_but(col, "use_map_kink_freq", "kink_freq_factor", "Kink Frequency")
factor_but(col, "use_map_rough", "rough_factor", "Rough")
elif isinstance(idblock, FreestyleLineStyle):
split = layout.split()
@@ -1187,18 +1133,17 @@ class TEXTURE_PT_influence(TextureSlotPanel, Panel):
layout.separator()
if not isinstance(idblock, ParticleSettings):
split = layout.split()
split = layout.split()
col = split.column()
col.prop(tex, "blend_type", text="Blend")
col.prop(tex, "use_rgb_to_intensity")
# color is used on gray-scale textures even when use_rgb_to_intensity is disabled.
col.prop(tex, "color", text="")
col = split.column()
col.prop(tex, "blend_type", text="Blend")
col.prop(tex, "use_rgb_to_intensity")
# color is used on gray-scale textures even when use_rgb_to_intensity is disabled.
col.prop(tex, "color", text="")
col = split.column()
col.prop(tex, "invert", text="Negative")
col.prop(tex, "use_stencil")
col = split.column()
col.prop(tex, "invert", text="Negative")
col.prop(tex, "use_stencil")
if isinstance(idblock, Material) or isinstance(idblock, World):
col.prop(tex, "default_value", text="DVar", slider=True)

View File

@@ -92,8 +92,6 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False):
row.prop(dopesheet, "show_lattices", text="")
if bpy.data.armatures:
row.prop(dopesheet, "show_armatures", text="")
if bpy.data.particles:
row.prop(dopesheet, "show_particles", text="")
if bpy.data.speakers:
row.prop(dopesheet, "show_speakers", text="")
if bpy.data.linestyles:

View File

@@ -167,7 +167,6 @@ class TIME_MT_cache(Menu):
col = layout.column()
col.enabled = st.show_cache
col.prop(st, "cache_softbody")
col.prop(st, "cache_particles")
col.prop(st, "cache_cloth")
col.prop(st, "cache_smoke")
col.prop(st, "cache_dynamicpaint")

View File

@@ -371,7 +371,6 @@ class USERPREF_PT_edit(Panel):
col.prop(edit, "use_duplicate_texture", text="Texture")
#col.prop(edit, "use_duplicate_fcurve", text="F-Curve")
col.prop(edit, "use_duplicate_action", text="Action")
col.prop(edit, "use_duplicate_particle", text="Particle")
class USERPREF_PT_system(Panel):

View File

@@ -47,12 +47,9 @@ class VIEW3D_HT_header(Header):
if obj:
mode = obj.mode
# Particle edit
if mode == 'PARTICLE_EDIT':
row.prop(toolsettings.particle_edit, "select_mode", text="", expand=True)
# Occlude geometry
if ((view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'} and (mode == 'PARTICLE_EDIT' or (mode == 'EDIT' and obj.type == 'MESH'))) or
if ((view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'} and (mode == 'EDIT' and obj.type == 'MESH')) or
(mode == 'WEIGHT_PAINT')):
row.prop(view, "use_occlude_geometry", text="")
@@ -62,7 +59,7 @@ class VIEW3D_HT_header(Header):
row.prop(toolsettings, "proportional_edit", icon_only=True)
if toolsettings.proportional_edit != 'DISABLED':
row.prop(toolsettings, "proportional_edit_falloff", icon_only=True)
elif mode in {'EDIT', 'PARTICLE_EDIT'}:
elif mode == 'EDIT':
row = layout.row(align=True)
row.prop(toolsettings, "proportional_edit", icon_only=True)
if toolsettings.proportional_edit != 'DISABLED':
@@ -675,35 +672,6 @@ class VIEW3D_MT_select_pose(Menu):
layout.operator("object.select_pattern", text="Select Pattern...")
class VIEW3D_MT_select_particle(Menu):
bl_label = "Select"
def draw(self, context):
layout = self.layout
layout.operator("view3d.select_border")
layout.separator()
layout.operator("particle.select_all").action = 'TOGGLE'
layout.operator("particle.select_linked")
layout.operator("particle.select_all", text="Inverse").action = 'INVERT'
layout.separator()
layout.operator("particle.select_more")
layout.operator("particle.select_less")
layout.separator()
layout.operator("particle.select_random")
layout.separator()
layout.operator("particle.select_roots", text="Roots")
layout.operator("particle.select_tips", text="Tips")
class VIEW3D_MT_edit_mesh_select_similar(Menu):
bl_label = "Select Similar"
@@ -1874,85 +1842,6 @@ class VIEW3D_MT_hide_mask(Menu):
props = layout.operator("paint.mask_lasso_gesture", text="Lasso Mask")
# ********** Particle menu **********
class VIEW3D_MT_particle(Menu):
bl_label = "Particle"
def draw(self, context):
layout = self.layout
particle_edit = context.tool_settings.particle_edit
layout.operator("ed.undo")
layout.operator("ed.redo")
layout.operator("ed.undo_history")
layout.separator()
layout.operator("particle.mirror")
layout.separator()
layout.operator("particle.remove_doubles")
layout.operator("particle.delete")
if particle_edit.select_mode == 'POINT':
layout.operator("particle.subdivide")
layout.operator("particle.rekey")
layout.operator("particle.weight_set")
layout.separator()
layout.menu("VIEW3D_MT_particle_showhide")
class VIEW3D_MT_particle_specials(Menu):
bl_label = "Specials"
def draw(self, context):
layout = self.layout
particle_edit = context.tool_settings.particle_edit
layout.operator("particle.rekey")
layout.operator("particle.delete")
layout.operator("particle.remove_doubles")
if particle_edit.select_mode == 'POINT':
layout.operator("particle.subdivide")
layout.operator("particle.weight_set")
layout.separator()
layout.operator("particle.mirror")
if particle_edit.select_mode == 'POINT':
layout.separator()
layout.operator("particle.select_roots")
layout.operator("particle.select_tips")
layout.separator()
layout.operator("particle.select_random")
layout.separator()
layout.operator("particle.select_more")
layout.operator("particle.select_less")
layout.separator()
layout.operator("particle.select_all").action = 'TOGGLE'
layout.operator("particle.select_linked")
layout.operator("particle.select_all", text="Inverse").action = 'INVERT'
class VIEW3D_MT_particle_showhide(ShowHideMenu, Menu):
_operator_name = "particle"
# ********** Pose Menu **********

View File

@@ -881,37 +881,12 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
settings = self.paint_settings(context)
brush = settings.brush
if not context.particle_edit_object:
col = layout.split().column()
col.template_ID_preview(settings, "brush", new="brush.add", rows=3, cols=8)
# Particle Mode #
if context.particle_edit_object:
tool = settings.tool
layout.column().prop(settings, "tool", expand=True)
if tool != 'NONE':
col = layout.column()
col.prop(brush, "size", slider=True)
if tool != 'ADD':
col.prop(brush, "strength", slider=True)
if tool == 'ADD':
col.prop(brush, "count")
col = layout.column()
col.prop(settings, "use_default_interpolate")
col.prop(brush, "steps", slider=True)
col.prop(settings, "default_key_count", slider=True)
elif tool == 'LENGTH':
layout.prop(brush, "length_mode", expand=True)
elif tool == 'PUFF':
layout.prop(brush, "puff_mode", expand=True)
layout.prop(brush, "use_puff_volume")
col = layout.split().column()
col.template_ID_preview(settings, "brush", new="brush.add", rows=3, cols=8)
# Sculpt Mode #
elif context.sculpt_object and brush:
if context.sculpt_object and brush:
capabilities = brush.sculpt_capabilities
col = layout.column()
@@ -1592,7 +1567,7 @@ class VIEW3D_PT_tools_brush_appearance(Panel, View3DPaintPanel):
@classmethod
def poll(cls, context):
settings = cls.paint_settings(context)
return (settings is not None) and (not isinstance(settings, bpy.types.ParticleEdit))
return (settings is not None)
def draw(self, context):
layout = self.layout
@@ -1815,78 +1790,6 @@ class VIEW3D_MT_tools_projectpaint_stencil(Menu):
props.value = i
class VIEW3D_PT_tools_particlemode(View3DPanel, Panel):
"""Default tools for particle mode"""
bl_context = "particlemode"
bl_label = "Options"
bl_category = "Tools"
def draw(self, context):
layout = self.layout
pe = context.tool_settings.particle_edit
ob = pe.object
layout.prop(pe, "type", text="")
ptcache = None
if pe.type == 'PARTICLES':
if ob.particle_systems:
if len(ob.particle_systems) > 1:
layout.template_list("UI_UL_list", "particle_systems", ob, "particle_systems",
ob.particle_systems, "active_index", rows=2, maxrows=3)
ptcache = ob.particle_systems.active.point_cache
else:
for md in ob.modifiers:
if md.type == pe.type:
ptcache = md.point_cache
if ptcache and len(ptcache.point_caches) > 1:
layout.template_list("UI_UL_list", "particles_point_caches", ptcache, "point_caches",
ptcache.point_caches, "active_index", rows=2, maxrows=3)
if not pe.is_editable:
layout.label(text="Point cache must be baked")
layout.label(text="in memory to enable editing!")
col = layout.column(align=True)
if pe.is_hair:
col.active = pe.is_editable
col.prop(pe, "use_emitter_deflect", text="Deflect emitter")
sub = col.row(align=True)
sub.active = pe.use_emitter_deflect
sub.prop(pe, "emitter_distance", text="Distance")
col = layout.column(align=True)
col.active = pe.is_editable
col.label(text="Keep:")
col.prop(pe, "use_preserve_length", text="Lengths")
col.prop(pe, "use_preserve_root", text="Root")
if not pe.is_hair:
col.label(text="Correct:")
col.prop(pe, "use_auto_velocity", text="Velocity")
col.prop(ob.data, "use_mirror_x")
col.prop(pe, "shape_object")
col.operator("particle.shape_cut")
col = layout.column(align=True)
col.active = pe.is_editable
col.label(text="Draw:")
col.prop(pe, "draw_step", text="Path Steps")
if pe.is_hair:
col.prop(pe, "show_particles", text="Children")
else:
if pe.type == 'PARTICLES':
col.prop(pe, "show_particles", text="Particles")
col.prop(pe, "use_fade_time")
sub = col.row(align=True)
sub.active = pe.use_fade_time
sub.prop(pe, "fade_frames", slider=True)
# Grease Pencil drawing tools
class VIEW3D_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
bl_space_type = 'VIEW_3D'