forked from bartvdbraak/blender
b2a5f28421
Added a convenience operator to the Follow Path constraint which adds a F-Curve for the path (or the operator's "fixed position" value if no path is assigned), with options for setting the start frame and length of motion. This makes it easier for common users to just set up a quick follow-path animation where the camera (e.g. flying around a set over certain number of frames). A key advantage of this is that it takes care of the underlying math required for setting up the generator curve accordingly (I've got some plans for making this a bit friendlier to use later). Now, animating the paths is a one-click operation, with the start and length properties able to be controlled using the operator properties.
877 lines
27 KiB
Python
877 lines
27 KiB
Python
# ##### 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
|
|
|
|
|
|
class ConstraintButtonsPanel():
|
|
bl_space_type = 'PROPERTIES'
|
|
bl_region_type = 'WINDOW'
|
|
bl_context = "constraint"
|
|
|
|
def draw_constraint(self, context, con):
|
|
layout = self.layout
|
|
|
|
box = layout.template_constraint(con)
|
|
|
|
if box:
|
|
# match enum type to our functions, avoids a lookup table.
|
|
getattr(self, con.type)(context, box, con)
|
|
|
|
if con.type not in {'RIGID_BODY_JOINT', 'NULL'}:
|
|
box.prop(con, "influence")
|
|
|
|
def space_template(self, layout, con, target=True, owner=True):
|
|
if target or owner:
|
|
|
|
split = layout.split(percentage=0.2)
|
|
|
|
split.label(text="Space:")
|
|
row = split.row()
|
|
|
|
if target:
|
|
row.prop(con, "target_space", text="")
|
|
|
|
if target and owner:
|
|
row.label(icon='ARROW_LEFTRIGHT')
|
|
|
|
if owner:
|
|
row.prop(con, "owner_space", text="")
|
|
|
|
def target_template(self, layout, con, subtargets=True):
|
|
layout.prop(con, "target") # XXX limiting settings for only 'curves' or some type of object
|
|
|
|
if con.target and subtargets:
|
|
if con.target.type == 'ARMATURE':
|
|
layout.prop_search(con, "subtarget", con.target.data, "bones", text="Bone")
|
|
|
|
if hasattr(con, "head_tail"):
|
|
row = layout.row()
|
|
row.label(text="Head/Tail:")
|
|
row.prop(con, "head_tail", text="")
|
|
elif con.target.type in {'MESH', 'LATTICE'}:
|
|
layout.prop_search(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
|
|
|
|
def ik_template(self, layout, con):
|
|
# only used for iTaSC
|
|
layout.prop(con, "pole_target")
|
|
|
|
if con.pole_target and con.pole_target.type == 'ARMATURE':
|
|
layout.prop_search(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
|
|
|
|
if con.pole_target:
|
|
row = layout.row()
|
|
row.label()
|
|
row.prop(con, "pole_angle")
|
|
|
|
split = layout.split(percentage=0.33)
|
|
col = split.column()
|
|
col.prop(con, "use_tail")
|
|
col.prop(con, "use_stretch")
|
|
|
|
col = split.column()
|
|
col.prop(con, "chain_count")
|
|
col.prop(con, "use_target")
|
|
|
|
def CHILD_OF(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
|
|
split = layout.split()
|
|
|
|
col = split.column()
|
|
col.label(text="Location:")
|
|
col.prop(con, "use_location_x", text="X")
|
|
col.prop(con, "use_location_y", text="Y")
|
|
col.prop(con, "use_location_z", text="Z")
|
|
|
|
col = split.column()
|
|
col.label(text="Rotation:")
|
|
col.prop(con, "use_rotation_x", text="X")
|
|
col.prop(con, "use_rotation_y", text="Y")
|
|
col.prop(con, "use_rotation_z", text="Z")
|
|
|
|
col = split.column()
|
|
col.label(text="Scale:")
|
|
col.prop(con, "use_scale_x", text="X")
|
|
col.prop(con, "use_scale_y", text="Y")
|
|
col.prop(con, "use_scale_z", text="Z")
|
|
|
|
row = layout.row()
|
|
row.operator("constraint.childof_set_inverse")
|
|
row.operator("constraint.childof_clear_inverse")
|
|
|
|
def TRACK_TO(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
|
|
row = layout.row()
|
|
row.label(text="To:")
|
|
row.prop(con, "track_axis", expand=True)
|
|
|
|
row = layout.row()
|
|
row.prop(con, "up_axis", text="Up")
|
|
row.prop(con, "use_target_z")
|
|
|
|
self.space_template(layout, con)
|
|
|
|
def IK(self, context, layout, con):
|
|
if context.object.pose.ik_solver == 'ITASC':
|
|
layout.prop(con, "ik_type")
|
|
getattr(self, 'IK_' + con.ik_type)(context, layout, con)
|
|
else:
|
|
# Legacy IK constraint
|
|
self.target_template(layout, con)
|
|
layout.prop(con, "pole_target")
|
|
|
|
if con.pole_target and con.pole_target.type == 'ARMATURE':
|
|
layout.prop_search(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
|
|
|
|
if con.pole_target:
|
|
row = layout.row()
|
|
row.prop(con, "pole_angle")
|
|
row.label()
|
|
|
|
split = layout.split()
|
|
col = split.column()
|
|
col.prop(con, "iterations")
|
|
col.prop(con, "chain_count")
|
|
|
|
col.label(text="Weight:")
|
|
col.prop(con, "weight", text="Position", slider=True)
|
|
sub = col.column()
|
|
sub.active = con.use_rotation
|
|
sub.prop(con, "orient_weight", text="Rotation", slider=True)
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_tail")
|
|
col.prop(con, "use_stretch")
|
|
col.separator()
|
|
col.prop(con, "use_target")
|
|
col.prop(con, "use_rotation")
|
|
|
|
def IK_COPY_POSE(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
self.ik_template(layout, con)
|
|
|
|
row = layout.row()
|
|
row.label(text="Axis Ref:")
|
|
row.prop(con, "reference_axis", expand=True)
|
|
split = layout.split(percentage=0.33)
|
|
split.row().prop(con, "use_location")
|
|
row = split.row()
|
|
row.prop(con, "weight", text="Weight", slider=True)
|
|
row.active = con.use_location
|
|
split = layout.split(percentage=0.33)
|
|
row = split.row()
|
|
row.label(text="Lock:")
|
|
row = split.row()
|
|
row.prop(con, "lock_location_x", text="X")
|
|
row.prop(con, "lock_location_y", text="Y")
|
|
row.prop(con, "lock_location_z", text="Z")
|
|
split.active = con.use_location
|
|
|
|
split = layout.split(percentage=0.33)
|
|
split.row().prop(con, "use_rotation")
|
|
row = split.row()
|
|
row.prop(con, "orient_weight", text="Weight", slider=True)
|
|
row.active = con.use_rotation
|
|
split = layout.split(percentage=0.33)
|
|
row = split.row()
|
|
row.label(text="Lock:")
|
|
row = split.row()
|
|
row.prop(con, "lock_rotation_x", text="X")
|
|
row.prop(con, "lock_rotation_y", text="Y")
|
|
row.prop(con, "lock_rotation_z", text="Z")
|
|
split.active = con.use_rotation
|
|
|
|
def IK_DISTANCE(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
self.ik_template(layout, con)
|
|
|
|
layout.prop(con, "limit_mode")
|
|
|
|
row = layout.row()
|
|
row.prop(con, "weight", text="Weight", slider=True)
|
|
row.prop(con, "distance", text="Distance", slider=True)
|
|
|
|
def FOLLOW_PATH(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
layout.operator("constraint.followpath_path_animate", text="Animate Path", icon='ANIM_DATA')
|
|
|
|
split = layout.split()
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_curve_follow")
|
|
col.prop(con, "use_curve_radius")
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_fixed_location")
|
|
if con.use_fixed_location:
|
|
col.prop(con, "offset_factor", text="Offset")
|
|
else:
|
|
col.prop(con, "offset")
|
|
|
|
row = layout.row()
|
|
row.label(text="Forward:")
|
|
row.prop(con, "forward_axis", expand=True)
|
|
|
|
row = layout.row()
|
|
row.prop(con, "up_axis", text="Up")
|
|
row.label()
|
|
|
|
def LIMIT_ROTATION(self, context, layout, con):
|
|
split = layout.split()
|
|
|
|
col = split.column(align=True)
|
|
col.prop(con, "use_limit_x")
|
|
sub = col.column()
|
|
sub.active = con.use_limit_x
|
|
sub.prop(con, "min_x", text="Min")
|
|
sub.prop(con, "max_x", text="Max")
|
|
|
|
col = split.column(align=True)
|
|
col.prop(con, "use_limit_y")
|
|
sub = col.column()
|
|
sub.active = con.use_limit_y
|
|
sub.prop(con, "min_y", text="Min")
|
|
sub.prop(con, "max_y", text="Max")
|
|
|
|
col = split.column(align=True)
|
|
col.prop(con, "use_limit_z")
|
|
sub = col.column()
|
|
sub.active = con.use_limit_z
|
|
sub.prop(con, "min_z", text="Min")
|
|
sub.prop(con, "max_z", text="Max")
|
|
|
|
layout.prop(con, "use_transform_limit")
|
|
|
|
row = layout.row()
|
|
row.label(text="Convert:")
|
|
row.prop(con, "owner_space", text="")
|
|
|
|
def LIMIT_LOCATION(self, context, layout, con):
|
|
split = layout.split()
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_min_x")
|
|
sub = col.column()
|
|
sub.active = con.use_min_x
|
|
sub.prop(con, "min_x", text="")
|
|
col.prop(con, "use_max_x")
|
|
sub = col.column()
|
|
sub.active = con.use_max_x
|
|
sub.prop(con, "max_x", text="")
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_min_y")
|
|
sub = col.column()
|
|
sub.active = con.use_min_y
|
|
sub.prop(con, "min_y", text="")
|
|
col.prop(con, "use_max_y")
|
|
sub = col.column()
|
|
sub.active = con.use_max_y
|
|
sub.prop(con, "max_y", text="")
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_min_z")
|
|
sub = col.column()
|
|
sub.active = con.use_min_z
|
|
sub.prop(con, "min_z", text="")
|
|
col.prop(con, "use_max_z")
|
|
sub = col.column()
|
|
sub.active = con.use_max_z
|
|
sub.prop(con, "max_z", text="")
|
|
|
|
row = layout.row()
|
|
row.prop(con, "use_transform_limit")
|
|
row.label()
|
|
|
|
row = layout.row()
|
|
row.label(text="Convert:")
|
|
row.prop(con, "owner_space", text="")
|
|
|
|
def LIMIT_SCALE(self, context, layout, con):
|
|
split = layout.split()
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_min_x")
|
|
sub = col.column()
|
|
sub.active = con.use_min_x
|
|
sub.prop(con, "min_x", text="")
|
|
col.prop(con, "use_max_x")
|
|
sub = col.column()
|
|
sub.active = con.use_max_x
|
|
sub.prop(con, "max_x", text="")
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_min_y")
|
|
sub = col.column()
|
|
sub.active = con.use_min_y
|
|
sub.prop(con, "min_y", text="")
|
|
col.prop(con, "use_max_y")
|
|
sub = col.column()
|
|
sub.active = con.use_max_y
|
|
sub.prop(con, "max_y", text="")
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_min_z")
|
|
sub = col.column()
|
|
sub.active = con.use_min_z
|
|
sub.prop(con, "min_z", text="")
|
|
col.prop(con, "use_max_z")
|
|
sub = col.column()
|
|
sub.active = con.use_max_z
|
|
sub.prop(con, "max_z", text="")
|
|
|
|
row = layout.row()
|
|
row.prop(con, "use_transform_limit")
|
|
row.label()
|
|
|
|
row = layout.row()
|
|
row.label(text="Convert:")
|
|
row.prop(con, "owner_space", text="")
|
|
|
|
def COPY_ROTATION(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
|
|
split = layout.split()
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_x", text="X")
|
|
sub = col.column()
|
|
sub.active = con.use_x
|
|
sub.prop(con, "invert_x", text="Invert")
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_y", text="Y")
|
|
sub = col.column()
|
|
sub.active = con.use_y
|
|
sub.prop(con, "invert_y", text="Invert")
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_z", text="Z")
|
|
sub = col.column()
|
|
sub.active = con.use_z
|
|
sub.prop(con, "invert_z", text="Invert")
|
|
|
|
layout.prop(con, "use_offset")
|
|
|
|
self.space_template(layout, con)
|
|
|
|
def COPY_LOCATION(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
|
|
split = layout.split()
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_x", text="X")
|
|
sub = col.column()
|
|
sub.active = con.use_x
|
|
sub.prop(con, "invert_x", text="Invert")
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_y", text="Y")
|
|
sub = col.column()
|
|
sub.active = con.use_y
|
|
sub.prop(con, "invert_y", text="Invert")
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_z", text="Z")
|
|
sub = col.column()
|
|
sub.active = con.use_z
|
|
sub.prop(con, "invert_z", text="Invert")
|
|
|
|
layout.prop(con, "use_offset")
|
|
|
|
self.space_template(layout, con)
|
|
|
|
def COPY_SCALE(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
|
|
row = layout.row(align=True)
|
|
row.prop(con, "use_x", text="X")
|
|
row.prop(con, "use_y", text="Y")
|
|
row.prop(con, "use_z", text="Z")
|
|
|
|
layout.prop(con, "use_offset")
|
|
|
|
self.space_template(layout, con)
|
|
|
|
def MAINTAIN_VOLUME(self, context, layout, con):
|
|
|
|
row = layout.row()
|
|
row.label(text="Free:")
|
|
row.prop(con, "free_axis", expand=True)
|
|
|
|
layout.prop(con, "volume")
|
|
|
|
row = layout.row()
|
|
row.label(text="Convert:")
|
|
row.prop(con, "owner_space", text="")
|
|
|
|
def COPY_TRANSFORMS(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
|
|
self.space_template(layout, con)
|
|
|
|
#def SCRIPT(self, context, layout, con):
|
|
|
|
def ACTION(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
|
|
split = layout.split()
|
|
|
|
col = split.column()
|
|
col.label(text="From Target:")
|
|
col.prop(con, "transform_channel", text="")
|
|
col.prop(con, "target_space", text="")
|
|
|
|
col = split.column()
|
|
col.label(text="To Action:")
|
|
col.prop(con, "action", text="")
|
|
col.prop(con, "use_bone_object_action")
|
|
|
|
split = layout.split()
|
|
|
|
col = split.column(align=True)
|
|
col.label(text="Target Range:")
|
|
col.prop(con, "min", text="Min")
|
|
col.prop(con, "max", text="Max")
|
|
|
|
col = split.column(align=True)
|
|
col.label(text="Action Range:")
|
|
col.prop(con, "frame_start", text="Start")
|
|
col.prop(con, "frame_end", text="End")
|
|
|
|
def LOCKED_TRACK(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
|
|
row = layout.row()
|
|
row.label(text="To:")
|
|
row.prop(con, "track_axis", expand=True)
|
|
|
|
row = layout.row()
|
|
row.label(text="Lock:")
|
|
row.prop(con, "lock_axis", expand=True)
|
|
|
|
def LIMIT_DISTANCE(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
|
|
col = layout.column(align=True)
|
|
col.prop(con, "distance")
|
|
col.operator("constraint.limitdistance_reset")
|
|
|
|
row = layout.row()
|
|
row.label(text="Clamp Region:")
|
|
row.prop(con, "limit_mode", text="")
|
|
|
|
row = layout.row()
|
|
row.prop(con, "use_transform_limit")
|
|
row.label()
|
|
|
|
def STRETCH_TO(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
|
|
row = layout.row()
|
|
row.prop(con, "rest_length", text="Rest Length")
|
|
row.operator("constraint.stretchto_reset", text="Reset")
|
|
|
|
layout.prop(con, "bulge", text="Volume Variation")
|
|
|
|
row = layout.row()
|
|
row.label(text="Volume:")
|
|
row.prop(con, "volume", expand=True)
|
|
|
|
row.label(text="Plane:")
|
|
row.prop(con, "keep_axis", expand=True)
|
|
|
|
def FLOOR(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
|
|
row = layout.row()
|
|
row.prop(con, "use_sticky")
|
|
row.prop(con, "use_rotation")
|
|
|
|
layout.prop(con, "offset")
|
|
|
|
row = layout.row()
|
|
row.label(text="Min/Max:")
|
|
row.prop(con, "floor_location", expand=True)
|
|
|
|
self.space_template(layout, con)
|
|
|
|
def RIGID_BODY_JOINT(self, context, layout, con):
|
|
self.target_template(layout, con, subtargets=False)
|
|
|
|
layout.prop(con, "pivot_type")
|
|
layout.prop(con, "child")
|
|
|
|
row = layout.row()
|
|
row.prop(con, "use_linked_collision", text="Linked Collision")
|
|
row.prop(con, "show_pivot", text="Display Pivot")
|
|
|
|
split = layout.split()
|
|
|
|
col = split.column(align=True)
|
|
col.label(text="Pivot:")
|
|
col.prop(con, "pivot_x", text="X")
|
|
col.prop(con, "pivot_y", text="Y")
|
|
col.prop(con, "pivot_z", text="Z")
|
|
|
|
col = split.column(align=True)
|
|
col.label(text="Axis:")
|
|
col.prop(con, "axis_x", text="X")
|
|
col.prop(con, "axis_y", text="Y")
|
|
col.prop(con, "axis_z", text="Z")
|
|
|
|
if con.pivot_type == 'CONE_TWIST':
|
|
layout.label(text="Limits:")
|
|
split = layout.split()
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_angular_limit_x", text="Angle X")
|
|
sub = col.column()
|
|
sub.active = con.use_angular_limit_x
|
|
sub.prop(con, "limit_angle_max_x", text="")
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_angular_limit_y", text="Angle Y")
|
|
sub = col.column()
|
|
sub.active = con.use_angular_limit_y
|
|
sub.prop(con, "limit_angle_max_y", text="")
|
|
|
|
col = split.column()
|
|
col.prop(con, "use_angular_limit_z", text="Angle Z")
|
|
sub = col.column()
|
|
sub.active = con.use_angular_limit_z
|
|
sub.prop(con, "limit_angle_max_z", text="")
|
|
|
|
elif con.pivot_type == 'GENERIC_6_DOF':
|
|
layout.label(text="Limits:")
|
|
split = layout.split()
|
|
|
|
col = split.column(align=True)
|
|
col.prop(con, "use_limit_x", text="X")
|
|
sub = col.column()
|
|
sub.active = con.use_limit_x
|
|
sub.prop(con, "limit_min_x", text="Min")
|
|
sub.prop(con, "limit_max_x", text="Max")
|
|
|
|
col = split.column(align=True)
|
|
col.prop(con, "use_limit_y", text="Y")
|
|
sub = col.column()
|
|
sub.active = con.use_limit_y
|
|
sub.prop(con, "limit_min_y", text="Min")
|
|
sub.prop(con, "limit_max_y", text="Max")
|
|
|
|
col = split.column(align=True)
|
|
col.prop(con, "use_limit_z", text="Z")
|
|
sub = col.column()
|
|
sub.active = con.use_limit_z
|
|
sub.prop(con, "limit_min_z", text="Min")
|
|
sub.prop(con, "limit_max_z", text="Max")
|
|
|
|
split = layout.split()
|
|
|
|
col = split.column(align=True)
|
|
col.prop(con, "use_angular_limit_x", text="Angle X")
|
|
sub = col.column()
|
|
sub.active = con.use_angular_limit_x
|
|
sub.prop(con, "limit_angle_min_x", text="Min")
|
|
sub.prop(con, "limit_angle_max_x", text="Max")
|
|
|
|
col = split.column(align=True)
|
|
col.prop(con, "use_angular_limit_y", text="Angle Y")
|
|
sub = col.column()
|
|
sub.active = con.use_angular_limit_y
|
|
sub.prop(con, "limit_angle_min_y", text="Min")
|
|
sub.prop(con, "limit_angle_max_y", text="Max")
|
|
|
|
col = split.column(align=True)
|
|
col.prop(con, "use_angular_limit_z", text="Angle Z")
|
|
sub = col.column()
|
|
sub.active = con.use_angular_limit_z
|
|
sub.prop(con, "limit_angle_min_z", text="Min")
|
|
sub.prop(con, "limit_angle_max_z", text="Max")
|
|
|
|
elif con.pivot_type == 'HINGE':
|
|
layout.label(text="Limits:")
|
|
split = layout.split()
|
|
|
|
row = split.row(align=True)
|
|
col = row.column()
|
|
col.prop(con, "use_angular_limit_x", text="Angle X")
|
|
|
|
col = row.column()
|
|
col.active = con.use_angular_limit_x
|
|
col.prop(con, "limit_angle_min_x", text="Min")
|
|
col = row.column()
|
|
col.active = con.use_angular_limit_x
|
|
col.prop(con, "limit_angle_max_x", text="Max")
|
|
|
|
def CLAMP_TO(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
|
|
row = layout.row()
|
|
row.label(text="Main Axis:")
|
|
row.prop(con, "main_axis", expand=True)
|
|
|
|
layout.prop(con, "use_cyclic")
|
|
|
|
def TRANSFORM(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
|
|
layout.prop(con, "use_motion_extrapolate", text="Extrapolate")
|
|
|
|
col = layout.column()
|
|
col.row().label(text="Source:")
|
|
col.row().prop(con, "map_from", expand=True)
|
|
|
|
split = layout.split()
|
|
|
|
sub = split.column(align=True)
|
|
sub.label(text="X:")
|
|
sub.prop(con, "from_min_x", text="Min")
|
|
sub.prop(con, "from_max_x", text="Max")
|
|
|
|
sub = split.column(align=True)
|
|
sub.label(text="Y:")
|
|
sub.prop(con, "from_min_y", text="Min")
|
|
sub.prop(con, "from_max_y", text="Max")
|
|
|
|
sub = split.column(align=True)
|
|
sub.label(text="Z:")
|
|
sub.prop(con, "from_min_z", text="Min")
|
|
sub.prop(con, "from_max_z", text="Max")
|
|
|
|
col = layout.column()
|
|
row = col.row()
|
|
row.label(text="Source to Destination Mapping:")
|
|
|
|
# note: chr(187) is the ASCII arrow ( >> ). Blender Text Editor can't
|
|
# open it. Thus we are using the hard-coded value instead.
|
|
row = col.row()
|
|
row.prop(con, "map_to_x_from", expand=False, text="")
|
|
row.label(text=" %s X" % chr(187))
|
|
|
|
row = col.row()
|
|
row.prop(con, "map_to_y_from", expand=False, text="")
|
|
row.label(text=" %s Y" % chr(187))
|
|
|
|
row = col.row()
|
|
row.prop(con, "map_to_z_from", expand=False, text="")
|
|
row.label(text=" %s Z" % chr(187))
|
|
|
|
split = layout.split()
|
|
|
|
col = split.column()
|
|
col.label(text="Destination:")
|
|
col.row().prop(con, "map_to", expand=True)
|
|
|
|
split = layout.split()
|
|
|
|
col = split.column()
|
|
col.label(text="X:")
|
|
|
|
sub = col.column(align=True)
|
|
sub.prop(con, "to_min_x", text="Min")
|
|
sub.prop(con, "to_max_x", text="Max")
|
|
|
|
col = split.column()
|
|
col.label(text="Y:")
|
|
|
|
sub = col.column(align=True)
|
|
sub.prop(con, "to_min_y", text="Min")
|
|
sub.prop(con, "to_max_y", text="Max")
|
|
|
|
col = split.column()
|
|
col.label(text="Z:")
|
|
|
|
sub = col.column(align=True)
|
|
sub.prop(con, "to_min_z", text="Min")
|
|
sub.prop(con, "to_max_z", text="Max")
|
|
|
|
self.space_template(layout, con)
|
|
|
|
def SHRINKWRAP(self, context, layout, con):
|
|
self.target_template(layout, con, False)
|
|
|
|
layout.prop(con, "distance")
|
|
layout.prop(con, "shrinkwrap_type")
|
|
|
|
if con.shrinkwrap_type == 'PROJECT':
|
|
row = layout.row(align=True)
|
|
row.prop(con, "use_x")
|
|
row.prop(con, "use_y")
|
|
row.prop(con, "use_z")
|
|
|
|
def DAMPED_TRACK(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
|
|
row = layout.row()
|
|
row.label(text="To:")
|
|
row.prop(con, "track_axis", expand=True)
|
|
|
|
def SPLINE_IK(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
|
|
col = layout.column()
|
|
col.label(text="Spline Fitting:")
|
|
col.prop(con, "chain_count")
|
|
col.prop(con, "use_even_divisions")
|
|
col.prop(con, "use_chain_offset")
|
|
|
|
col = layout.column()
|
|
col.label(text="Chain Scaling:")
|
|
col.prop(con, "use_y_stretch")
|
|
col.prop(con, "xz_scale_mode")
|
|
col.prop(con, "use_curve_radius")
|
|
|
|
def PIVOT(self, context, layout, con):
|
|
self.target_template(layout, con)
|
|
|
|
if con.target:
|
|
col = layout.column()
|
|
col.prop(con, "offset", text="Pivot Offset")
|
|
else:
|
|
col = layout.column()
|
|
col.prop(con, "use_relative_location")
|
|
if con.use_relative_location:
|
|
col.prop(con, "offset", text="Relative Pivot Point")
|
|
else:
|
|
col.prop(con, "offset", text="Absolute Pivot Point")
|
|
|
|
col = layout.column()
|
|
col.prop(con, "rotation_range", text="Pivot When")
|
|
|
|
@staticmethod
|
|
def _getConstraintClip(context, con):
|
|
if not con.use_active_clip:
|
|
return con.clip
|
|
else:
|
|
return context.scene.active_clip
|
|
|
|
def FOLLOW_TRACK(self, context, layout, con):
|
|
clip = self._getConstraintClip(context, con)
|
|
|
|
row = layout.row()
|
|
row.prop(con, "use_active_clip")
|
|
row.prop(con, "use_3d_position")
|
|
|
|
col = layout.column()
|
|
|
|
if not con.use_active_clip:
|
|
col.prop(con, "clip")
|
|
|
|
row = col.row()
|
|
row.prop(con, "frame_method", expand=True)
|
|
|
|
if clip:
|
|
tracking = clip.tracking
|
|
|
|
col.prop_search(con, "object", tracking, "objects", icon='OBJECT_DATA')
|
|
|
|
tracking_object = tracking.objects.get(con.object, tracking.objects[0])
|
|
|
|
col.prop_search(con, "track", tracking_object, "tracks", icon='ANIM_DATA')
|
|
|
|
col.prop(con, "camera")
|
|
|
|
row = col.row()
|
|
row.active = not con.use_3d_position
|
|
row.prop(con, "depth_object")
|
|
|
|
layout.operator("clip.constraint_to_fcurve")
|
|
|
|
def CAMERA_SOLVER(self, context, layout, con):
|
|
layout.prop(con, "use_active_clip")
|
|
|
|
if not con.use_active_clip:
|
|
layout.prop(con, "clip")
|
|
|
|
layout.operator("clip.constraint_to_fcurve")
|
|
|
|
def OBJECT_SOLVER(self, context, layout, con):
|
|
clip = self._getConstraintClip(context, con)
|
|
|
|
layout.prop(con, "use_active_clip")
|
|
|
|
if not con.use_active_clip:
|
|
layout.prop(con, "clip")
|
|
|
|
if clip:
|
|
layout.prop_search(con, "object", clip.tracking, "objects", icon='OBJECT_DATA')
|
|
|
|
layout.prop(con, "camera")
|
|
|
|
row = layout.row()
|
|
row.operator("constraint.objectsolver_set_inverse")
|
|
row.operator("constraint.objectsolver_clear_inverse")
|
|
|
|
layout.operator("clip.constraint_to_fcurve")
|
|
|
|
def SCRIPT(self, context, layout, con):
|
|
layout.label("Blender 2.6 doesn't support python constraints yet.")
|
|
|
|
|
|
class OBJECT_PT_constraints(ConstraintButtonsPanel, Panel):
|
|
bl_label = "Object Constraints"
|
|
bl_context = "constraint"
|
|
bl_options = {'HIDE_HEADER'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return (context.object)
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
ob = context.object
|
|
|
|
if ob.mode == 'POSE':
|
|
box = layout.box()
|
|
box.alert = True
|
|
box.label(icon='INFO', text="See Bone Constraints tab to Add Constraints to active bone")
|
|
else:
|
|
layout.operator_menu_enum("object.constraint_add", "type")
|
|
|
|
for con in ob.constraints:
|
|
self.draw_constraint(context, con)
|
|
|
|
|
|
class BONE_PT_constraints(ConstraintButtonsPanel, Panel):
|
|
bl_label = "Bone Constraints"
|
|
bl_context = "bone_constraint"
|
|
bl_options = {'HIDE_HEADER'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return (context.pose_bone)
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
layout.operator_menu_enum("pose.constraint_add", "type")
|
|
|
|
for con in context.pose_bone.constraints:
|
|
self.draw_constraint(context, con)
|
|
|
|
if __name__ == "__main__": # only for live edit.
|
|
bpy.utils.register_module(__name__)
|