From a5b07c09349978ab7ecf319e6345d7c98177521c Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Tue, 24 May 2011 11:15:21 +0000 Subject: == Animated Transforms to Deltas == Added operator to convert animation for standard object transforms (i.e. loc/rot/scale) to delta transforms. This can be accessed from the Object -> Transform -> Animated Transforms To Deltas menu entry in the 3D View. Since the situation which causes this is quite common (especially for motion-graphics type applications), where users animate some object first and then decide to duplicate this and place it around the place in different locations, it's probably important that we have some support for this kind of thing. Newbies with the "help, all my anmated duplicates disappear" problem are recommended to use this operator from hereon in. For reference of rationale, see: http://blenderartists.org/forum/showthread.php?219126-Move-Existing-f -Curve-to-delta-equivalent --- release/scripts/startup/bl_operators/object.py | 41 ++++++++++++++++++++++++++ release/scripts/startup/bl_ui/space_view3d.py | 4 +++ 2 files changed, 45 insertions(+) (limited to 'release') diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py index 0342a14a1b2..7a9a9d41939 100644 --- a/release/scripts/startup/bl_operators/object.py +++ b/release/scripts/startup/bl_operators/object.py @@ -564,3 +564,44 @@ class ClearAllRestrictRender(bpy.types.Operator): for obj in context.scene.objects: obj.hide_render = False return {'FINISHED'} + +class TransformsToDeltasAnim(bpy.types.Operator): + '''Convert object animation for normal transforms to delta transforms''' + bl_idname = "object.anim_transforms_to_deltas" + bl_label = "Animated Transforms to Deltas" + bl_options = {'REGISTER', 'UNDO'} + + @classmethod + def poll(cls, context): + obs = context.selected_editable_objects + return (obs is not None) + + def execute(self, context): + for obj in context.selected_editable_objects: + # get animation data + adt = obj.animation_data + if (adt is None) or (adt.action is None): + self.report({'WARNING'}, "No animation data to convert on object: " + obj.name) + continue + + # if F-Curve uses standard transform path, just append "delta_" to this path + for fcu in adt.action.fcurves: + if fcu.data_path == "location": + fcu.data_path = "delta_location" + obj.location.zero() + elif fcu.data_path == "rotation_euler": + fcu.data_path = "delta_rotation_euler" + obj.rotation_euler.zero() + elif fcu.data_path == "rotation_quaternion": + fcu.data_path = "delta_rotation_quaternion" + obj.rotation_quaternion.identity() + #elif fcu.data_path == "rotation_axis_angle": # XXX: currently not implemented + # fcu.data_path = "delta_rotation_axis_angle" + elif fcu.data_path == "scale": + fcu.data_path = "delta_scale" + obj.scale = (1, 1, 1) + + # hack: force animsys flush by changing frame, so that deltas get run + context.scene.frame_set(context.scene.frame_current) + + return {'FINISHED'} diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index e6ce1d4c179..a4c2a7a4549 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -181,6 +181,10 @@ class VIEW3D_MT_transform(bpy.types.Menu): layout.operator("object.randomize_transform") layout.operator("object.align") + + layout.separator() + + layout.operator("object.anim_transforms_to_deltas") class VIEW3D_MT_mirror(bpy.types.Menu): -- cgit v1.2.3 From 1788bc298c7afc202346477ac14456f6f208359b Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Tue, 24 May 2011 12:12:12 +0000 Subject: = Limit Distance Constraint - 'For Transform' Option = The Limit Distance Constraint now has a "For Transform" option just like all the other Limit constraints. This option controls whether the constraint gets applied to interactive transforms in the 3D View too, preventing controllers from getting large values without the animator knowing. Additional code changes: * Split code to get constraint targets and grab their matrices for solving out to a separate helper function: get_constraint_targets_for_solving() * Fixed a bug where "found constraint ...." prints would appear in the console. Looks like some warning print that was forgotten TODO: * While coding this, I noticed potential division by zero bugs with the Limit Distance constraint. Looking into these after this commit. --- release/scripts/startup/bl_ui/properties_object_constraint.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/properties_object_constraint.py b/release/scripts/startup/bl_ui/properties_object_constraint.py index 2ca18744eb6..900570c9664 100644 --- a/release/scripts/startup/bl_ui/properties_object_constraint.py +++ b/release/scripts/startup/bl_ui/properties_object_constraint.py @@ -476,6 +476,11 @@ class ConstraintButtonsPanel(): 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) -- cgit v1.2.3 From 655fcfbcc0053b60bc7654b02708794518870dbd Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Wed, 25 May 2011 10:42:57 +0000 Subject: First commit of mocap_tools.py, contains functions for Fcurve simplification and loop detection of anims --- release/scripts/modules/mocap_tools.py | 451 +++++++++++++++++++++++++++++++++ 1 file changed, 451 insertions(+) create mode 100644 release/scripts/modules/mocap_tools.py (limited to 'release') diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py new file mode 100644 index 00000000000..739dc40b272 --- /dev/null +++ b/release/scripts/modules/mocap_tools.py @@ -0,0 +1,451 @@ +from math import hypot, sqrt, isfinite +import bpy +import time +from mathutils import Vector + +#Vector utility functions +class NdVector: + vec = [] + + def __init__(self,vec): + self.vec = vec[:] + + def __len__(self): + return len(self.vec) + + def __mul__(self,otherMember): + if type(otherMember)==type(1) or type(otherMember)==type(1.0): + return NdVector([otherMember*x for x in self.vec]) + else: + a = self.vec + b = otherMember.vec + n = len(self) + return sum([a[i]*b[i] for i in range(n)]) + + def __sub__(self,otherVec): + a = self.vec + b = otherVec.vec + n = len(self) + return NdVector([a[i]-b[i] for i in range(n)]) + + def __add__(self,otherVec): + a = self.vec + b = otherVec.vec + n = len(self) + return NdVector([a[i]+b[i] for i in range(n)]) + + def vecLength(self): + return sqrt(self * self) + + def vecLengthSq(self): + return (self * self) + + def __getitem__(self,i): + return self.vec[i] + + length = property(vecLength) + lengthSq = property(vecLengthSq) + +class dataPoint: + index = 0 + co = Vector((0,0,0,0)) # x,y1,y2,y3 coordinate of original point + u = 0 #position according to parametric view of original data, [0,1] range + temp = 0 #use this for anything + + def __init__(self,index,co,u=0): + self.index = index + self.co = co + self.u = u + +def autoloop_anim(): + context = bpy.context + obj = context.active_object + fcurves = [x for x in obj.animation_data.action.fcurves if x.select] + + data = [] + end = len(fcurves[0].keyframe_points) + + for i in range(1,end): + vec = [] + for fcurve in fcurves: + vec.append(fcurve.evaluate(i)) + data.append(NdVector(vec)) + + def comp(a,b): + return a*b + + N = len(data) + Rxy = [0.0] * N + for i in range(N): + for j in range(i,min(i+N,N)): + Rxy[i]+=comp(data[j],data[j-i]) + for j in range(i): + Rxy[i]+=comp(data[j],data[j-i+N]) + Rxy[i]/=float(N) + + def bestLocalMaximum(Rxy): + Rxyd = [Rxy[i]-Rxy[i-1] for i in range(1,len(Rxy))] + maxs = [] + for i in range(1,len(Rxyd)-1): + a = Rxyd[i-1] + b = Rxyd[i] + print(a,b) + if (a>=0 and b<0) or (a<0 and b>=0): #sign change (zerocrossing) at point i, denoting max point (only) + maxs.append((i,max(Rxy[i],Rxy[i-1]))) + return max(maxs,key=lambda x: x[1])[0] + flm = bestLocalMaximum(Rxy[0:int(len(Rxy))]) + + diff = [] + + for i in range(len(data)-flm): + diff.append((data[i]-data[i+flm]).lengthSq) + + def lowerErrorSlice(diff,e): + bestSlice = (0,100000) #index, error at index + for i in range(e,len(diff)-e): + errorSlice = sum(diff[i-e:i+e+1]) + if errorSlice= maxError: + maxError = tmpError + maxErrorPt = pt.index + return maxError,maxErrorPt + + + #calculated bezier derivative at point t. + #That is, tangent of point t. + def getBezDerivative(bez,t): + n = len(bez)-1 + sumVec = Vector((0,0,0,0)) + for i in range(n-1): + sumVec+=bernsteinPoly(n-1,i,t)*(bez[i+1]-bez[i]) + return sumVec + + + #use Newton-Raphson to find a better paramterization of datapoints, + #one that minimizes the distance (or error) between bezier and original data. + def newtonRaphson(data_pts,s,e,bez): + for pt in data_pts[s:e+1]: + if pt.index==s: + pt.u=0 + elif pt.index==e: + pt.u=1 + else: + u = pt.u + qu = bezierEval(bez,pt.u) + qud = getBezDerivative(bez,u) + #we wish to minimize f(u), the squared distance between curve and data + fu = (qu-pt.co).length**2 + fud = (2*(qu.x-pt.co.x)*(qud.x))-(2*(qu.y-pt.co.y)*(qud.y)) + if fud==0: + fu = 0 + fud = 1 + pt.u=pt.u-(fu/fud) + + def createDataPts(curveGroup, group_mode): + data_pts = [] + if group_mode: + for i in range(len(curveGroup[0].keyframe_points)): + x = curveGroup[0].keyframe_points[i].co.x + y1 = curveGroup[0].keyframe_points[i].co.y + y2 = curveGroup[1].keyframe_points[i].co.y + y3 = curveGroup[2].keyframe_points[i].co.y + data_pts.append(dataPoint(i,Vector((x,y1,y2,y3)))) + else: + for i in range(len(curveGroup.keyframe_points)): + x = curveGroup.keyframe_points[i].co.x + y1 = curveGroup.keyframe_points[i].co.y + y2 = 0 + y3 = 0 + data_pts.append(dataPoint(i,Vector((x,y1,y2,y3)))) + return data_pts + + def fitCubic(data_pts,s,e): + + if e-s<3: # if there are less than 3 points, fit a single basic bezier + bez = fitSingleCubic2Pts(data_pts,s,e) + else: + #if there are more, parameterize the points and fit a single cubic bezier + chordLength(data_pts,s,e) + bez = fitSingleCubic(data_pts,s,e) + + #calculate max error and point where it occurs + maxError,maxErrorPt = maxErrorAmount(data_pts,bez,s,e) + #if error is small enough, reparameterization might be enough + if maxErrorerror: + for i in range(maxIterations): + newtonRaphson(data_pts,s,e,bez) + if e-s<3: + bez = fitSingleCubic2Pts(data_pts,s,e) + else: + bez = fitSingleCubic(data_pts,s,e) + + + #recalculate max error and point where it occurs + maxError,maxErrorPt = maxErrorAmount(data_pts,bez,s,e) + + #repara wasn't enough, we need 2 beziers for this range. + #Split the bezier at point of maximum error + if maxError>error: + fitCubic(data_pts,s,maxErrorPt) + fitCubic(data_pts,maxErrorPt,e) + else: + #error is small enough, return the beziers. + beziers.append(bez) + return + + def createNewCurves(curveGroup,beziers,group_mode): + #remove all existing data points + if group_mode: + for fcurve in curveGroup: + for i in range(len(fcurve.keyframe_points)-1,0,-1): + fcurve.keyframe_points.remove(fcurve.keyframe_points[i]) + else: + fcurve = curveGroup + for i in range(len(fcurve.keyframe_points)-1,0,-1): + fcurve.keyframe_points.remove(fcurve.keyframe_points[i]) + + #insert the calculated beziers to blender data.\ + if group_mode: + for fullbez in beziers: + for i,fcurve in enumerate(curveGroup): + bez = [Vector((vec[0],vec[i+1])) for vec in fullbez] + newKey = fcurve.keyframe_points.insert(frame=bez[0].x,value=bez[0].y) + newKey.handle_right = (bez[1].x,bez[1].y) + + newKey = fcurve.keyframe_points.insert(frame=bez[3].x,value=bez[3].y) + newKey.handle_left= (bez[2].x,bez[2].y) + else: + for bez in beziers: + for vec in bez: + vec.resize_2d() + newKey = fcurve.keyframe_points.insert(frame=bez[0].x,value=bez[0].y) + newKey.handle_right = (bez[1].x,bez[1].y) + + newKey = fcurve.keyframe_points.insert(frame=bez[3].x,value=bez[3].y) + newKey.handle_left= (bez[2].x,bez[2].y) + + #indices are detached from data point's frame (x) value and stored in the dataPoint object, represent a range + + data_pts = createDataPts(curveGroup,group_mode) + + s = 0 #start + e = len(data_pts)-1 #end + + beziers = [] + + #begin the recursive fitting algorithm. + fitCubic(data_pts,s,e) + #remove old Fcurves and insert the new ones + createNewCurves(curveGroup,beziers,group_mode) + +#Main function of simplification +#sel_opt: either "sel" or "all" for which curves to effect +#error: maximum error allowed, in fraction (20% = 0.0020), i.e. divide by 10000 from percentage wanted. +#group_mode: boolean, to analyze each curve seperately or in groups, where group is all curves that effect the same property (e.g. a bone's x,y,z rotation) + +def fcurves_simplify(sel_opt="all", error=0.002, group_mode=True): + # main vars + context = bpy.context + obj = context.active_object + fcurves = obj.animation_data.action.fcurves + + if sel_opt=="sel": + sel_fcurves = [fcurve for fcurve in fcurves if fcurve.select] + else: + sel_fcurves = fcurves[:] + + #Error threshold for Newton Raphson reparamatizing + reparaError = error*32 + maxIterations = 16 + + if group_mode: + fcurveDict = {} + #this loop sorts all the fcurves into groups of 3, based on their RNA Data path, which corresponds to which property they effect + for curve in sel_fcurves: + if curve.data_path in fcurveDict: #if this bone has been added, append the curve to its list + fcurveDict[curve.data_path].append(curve) + else: + fcurveDict[curve.data_path] = [curve] #new bone, add a new dict value with this first curve + fcurveGroups = fcurveDict.values() + else: + fcurveGroups = sel_fcurves + + if error>0.00000: + #simplify every selected curve. + totalt = 0 + for i,fcurveGroup in enumerate(fcurveGroups): + print("Processing curve "+str(i+1)+"/"+str(len(fcurveGroups))) + t = time.clock() + simplifyCurves(fcurveGroup,error,reparaError,maxIterations,group_mode) + t = time.clock() - t + print(str(t)[:5]+" seconds to process last curve") + totalt+=t + print(str(totalt)[:5]+" seconds, total time elapsed") + + return + -- cgit v1.2.3 From e3a46d05a77582ce8c86bff4f0d2c76cea0dac4e Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 2 Jun 2011 13:03:46 +0000 Subject: Added operator to remove all useless unused actions from the current .blend file. * From operator search, find "Clear Useless Actions" * "Action library" actions are preserved by this operator. It targets actions without any F-Curves * By default, only actions which are single-user (where that user is a Fake user) will be targeted. This can be changed to have it target any "dangling" action that doesn't have any F-Curves * A save/reload cycle is still required to fully remove such Actions from the current file. Though at least now it's a simpler process to have these semi-automatically removed ;) --- release/scripts/startup/bl_operators/nla.py | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'release') diff --git a/release/scripts/startup/bl_operators/nla.py b/release/scripts/startup/bl_operators/nla.py index 923ca92a162..82849cca2cc 100644 --- a/release/scripts/startup/bl_operators/nla.py +++ b/release/scripts/startup/bl_operators/nla.py @@ -168,3 +168,37 @@ class BakeAction(bpy.types.Operator): def invoke(self, context, event): wm = context.window_manager return wm.invoke_props_dialog(self) + +################################# + +class ClearUselessActions(bpy.types.Operator): + '''Mark actions with no F-Curves for deletion after save+reload of file preserving "action libraries"''' + bl_idname = "anim.clear_useless_actions" + bl_label = "Clear Useless Actions" + bl_options = {'REGISTER', 'UNDO'} + + only_unused = BoolProperty(name="Only Unused", + description="Only unused (Fake User only) actions get considered", + default=True) + + @classmethod + def poll(cls, context): + return len(bpy.data.actions) != 0 + + def execute(self, context): + removed = 0 + + for action in bpy.data.actions: + # if only user is "fake" user... + if ((self.only_unused is False) or + (action.use_fake_user and action.users == 1)): + + # if it has F-Curves, then it's a "action library" (i.e. walk, wave, jump, etc.) + # and should be left alone as that's what fake users are for! + if not action.fcurves: + # mark action for deletion + action.user_clear() + removed += 1 + + self.report({'INFO'}, "Removed %d empty and/or fake-user only Actions" % (removed)) + return {'FINISHED'} -- cgit v1.2.3 From fbff066a70c23077c16899a74feb29096ce5a2e9 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Thu, 2 Jun 2011 17:19:07 +0000 Subject: 2nd commit of mine. Contains retarget.py, which has functions for retargeting an animated armature to a second one, given a user mapping of the hiearchy. Currently creates an intermediate skeleton that solves some of the major issues. WIP --- release/scripts/modules/retarget.py | 136 ++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 release/scripts/modules/retarget.py (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py new file mode 100644 index 00000000000..c7a482659ef --- /dev/null +++ b/release/scripts/modules/retarget.py @@ -0,0 +1,136 @@ +import bpy +from mathutils import * +from math import radians, acos +performer_obj = bpy.data.objects["performer"] +enduser_obj = bpy.data.objects["enduser"] +scene = bpy.context.scene + +# dictionary of mapping +bonemap = { "LeftFoot": ("DEF_Foot.L","DEF_Toes.L"), + "LeftUpLeg": "DEF_Thigh.L", + "Hips": "DEF_Hip", + "LowerBack": "DEF_Spine", + "Spine": "DEF_Torso", + "Neck": "DEF_Neck", + "Neck1": "DEF_Neck", + "Head": "DEF_Head", + "LeftShoulder": "DEF_Shoulder.L", + "LeftArm": "DEF_Forearm.L", + "LeftForeArm": "DEF_Arm.L", + "LeftHand": "DEF_Hand.L", + "RightShoulder": "DEF_Shoulder.R", + "RightArm": "DEF_Forearm.R", + "RightForeArm": "DEF_Arm.R", + "RightHand": "DEF_Hand.R", + "RightFoot": ("DEF_Foot.R","DEF_Toes.R"), + "RightUpLeg": "DEF_Thigh.R", + "RightLeg": "DEF_Shin.R", + "LeftLeg": "DEF_Shin.L"} +# creation of a reverse map +# multiple keys get mapped to list values +bonemapr = {} +for key in bonemap.keys(): + if not bonemap[key] in bonemapr: + if type(bonemap[key])==type((0,0)): + for key_x in bonemap[key]: + bonemapr[key_x] = [key] + else: + bonemapr[bonemap[key]] = [key] + else: + bonemapr[bonemap[key]].append(key) + +# list of empties created to keep track of "original" +# position data +# in final product, these locations can be stored as custom props + +constraints = [] + +#creation of intermediate armature +# the intermediate armature has the hiearchy of the end user, +# does not have rotation inheritence +# and bone roll is identical to the performer +# its purpose is to copy over the rotations +# easily while concentrating on the hierarchy changes +def createIntermediate(): + + #creates and keyframes an empty with its location + #the original position of the tail bone + #useful for storing the important data in the original motion + #i.e. using this empty to IK the chain to that pos. + def locOfOriginal(inter_bone,perf_bone): + if not perf_bone.name+"Org" in bpy.data.objects: + bpy.ops.object.add() + empty = bpy.context.active_object + empty.name = perf_bone.name+"Org" + empty = bpy.data.objects[perf_bone.name+"Org"] + offset = perf_bone.vector + scaling = perf_bone.length / inter_bone.length + offset/=scaling + empty.location = inter_bone.head + offset + empty.keyframe_insert("location") + + #Simple 1to1 retarget of a bone + def singleBoneRetarget(inter_bone,perf_bone): + perf_world_rotation = perf_bone.matrix * performer_obj.matrix_world + inter_world_base_rotation = inter_bone.bone.matrix_local * inter_obj.matrix_world + inter_world_base_inv = Matrix(inter_world_base_rotation) + inter_world_base_inv.invert() + return (inter_world_base_inv.to_3x3() * perf_world_rotation.to_3x3()).to_4x4() + + #uses 1to1 and interpolation/averaging to match many to 1 retarget + def manyPerfToSingleInterRetarget(inter_bone,performer_bones_s): + retarget_matrices = [singleBoneRetarget(inter_bone,perf_bone) for perf_bone in performer_bones_s] + lerp_matrix = Matrix() + for i in range(len(retarget_matrices)-1): + first_mat = retarget_matrices[i] + next_mat = retarget_matrices[i+1] + lerp_matrix = first_mat.lerp(next_mat,0.5) + return lerp_matrix + + #determines the type of hierachy change needed and calls the + #right function + def retargetPerfToInter(inter_bone): + if inter_bone.name in bonemapr.keys(): + perf_bone_name = bonemapr[inter_bone.name] + #is it a 1 to many? + if type(bonemap[perf_bone_name[0]])==type((0,0)): + perf_bone = performer_bones[perf_bone_name[0]] + if inter_bone.name == bonemap[perf_bone_name[0]][0]: + locOfOriginal(inter_bone,perf_bone) + else: + # then its either a many to 1 or 1 to 1 + + if len(perf_bone_name) > 1: + performer_bones_s = [performer_bones[name] for name in perf_bone_name] + #we need to map several performance bone to a single + inter_bone.matrix_basis = manyPerfToSingleInterRetarget(inter_bone,performer_bones_s) + else: + perf_bone = performer_bones[perf_bone_name[0]] + inter_bone.matrix_basis = singleBoneRetarget(inter_bone,perf_bone) + + inter_bone.keyframe_insert("rotation_quaternion") + for child in inter_bone.children: + retargetPerfToInter(child) + + #creates the intermediate armature object + bpy.ops.object.select_name(name="enduser",extend=False) + bpy.ops.object.duplicate(linked=False) + bpy.context.active_object.name = "intermediate" + inter_obj = bpy.context.active_object + bpy.ops.object.mode_set(mode='EDIT') + #resets roll + bpy.ops.armature.calculate_roll(type='Z') + bpy.ops.object.mode_set(mode="OBJECT") + performer_bones = performer_obj.pose.bones + inter_bones = inter_obj.pose.bones + + #clears inheritance + for inter_bone in inter_bones: + inter_bone.bone.use_inherit_rotation = False + + for t in range(1,150): + scene.frame_set(t) + inter_bone = inter_bones["DEF_Hip"] + retargetPerfToInter(inter_bone) + +createIntermediate() \ No newline at end of file -- cgit v1.2.3 From 56e20eafe90ba6082acad9f84da3a1dc69c987a0 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sat, 4 Jun 2011 01:54:34 +0000 Subject: User Pref to not overwrite Recent Files list everytime you open a new file This is just a more formalised version of a local hack I've been running locally for the past year now. It's especially useful when you want to maintain your own set of recently opened test files (or perhaps current project files), but then be able to quickly open some .blend files downloaded from the web (i.e. checking out some bug report, or how someone else sets up some node setup) without loosing/polluting your existing recent files list as a result of doing so, and having to either resort to some nasty methods to get it back. Of course, this is still really hacky, as for instance, it means that the currently opened file will not show up in the recent files list for quick reload. However, that's why this is a userpref :) --- release/scripts/startup/bl_ui/space_userpref.py | 1 + 1 file changed, 1 insertion(+) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index f018785a925..24d54a83334 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -743,6 +743,7 @@ class USERPREF_PT_file(bpy.types.Panel): col.prop(paths, "save_version") col.prop(paths, "recent_files") + col.prop(paths, "use_update_recent_files_on_load") col.prop(paths, "use_save_preview_images") col.label(text="Auto Save:") col.prop(paths, "use_auto_save_temporary_files") -- cgit v1.2.3 From ef5f78ecc7a6a7aac04207d3733087db8d03f5a6 Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Sun, 5 Jun 2011 22:06:29 +0000 Subject: 3D Audio GSoC: Making it possible to access blenders internal sounds via Python. --- release/scripts/modules/bpy_types.py | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'release') diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 3c1b454e72e..c30c893c9cc 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -409,6 +409,16 @@ class Text(bpy_types.ID): TypeMap = {} +class Sound(bpy_types.ID): + __slots__ = () + + @property + def factory(self): + """The aud.Factory object of the sound.""" + import aud + return aud._sound_from_pointer(self.as_pointer()) + + class RNAMeta(type): def __new__(cls, name, bases, classdict, **args): result = type.__new__(cls, name, bases, classdict) -- cgit v1.2.3 From e4500096a5a9650899966fee9fa86a190cf2af1f Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Thu, 9 Jun 2011 12:30:24 +0000 Subject: retarget.py updated with function to complete the retarget to the end user, with inheritance and bone roll taken under account --- release/scripts/modules/retarget.py | 66 +++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index c7a482659ef..b081191d9a6 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -3,9 +3,18 @@ from mathutils import * from math import radians, acos performer_obj = bpy.data.objects["performer"] enduser_obj = bpy.data.objects["enduser"] +end_arm = bpy.data.armatures["enduser_arm"] scene = bpy.context.scene +#TODO: Only selected bones get retargeted. +# Selected Bones/chains get original pos empties, if ppl want IK instead of FK +# Some "magic" numbers - frame start and end, eulers of all orders instead of just quats keyframed + + + # dictionary of mapping +# this is currently manuall input'ed, but will +# be created from a more comfortable UI in the future bonemap = { "LeftFoot": ("DEF_Foot.L","DEF_Toes.L"), "LeftUpLeg": "DEF_Thigh.L", "Hips": "DEF_Hip", @@ -26,6 +35,7 @@ bonemap = { "LeftFoot": ("DEF_Foot.L","DEF_Toes.L"), "RightUpLeg": "DEF_Thigh.R", "RightLeg": "DEF_Shin.R", "LeftLeg": "DEF_Shin.L"} + # creation of a reverse map # multiple keys get mapped to list values bonemapr = {} @@ -42,9 +52,11 @@ for key in bonemap.keys(): # list of empties created to keep track of "original" # position data # in final product, these locations can be stored as custom props +# these help with constraining, etc. constraints = [] + #creation of intermediate armature # the intermediate armature has the hiearchy of the end user, # does not have rotation inheritence @@ -103,9 +115,12 @@ def createIntermediate(): if len(perf_bone_name) > 1: performer_bones_s = [performer_bones[name] for name in perf_bone_name] #we need to map several performance bone to a single + for perf_bone in performer_bones_s: + locOfOriginal(inter_bone,perf_bone) inter_bone.matrix_basis = manyPerfToSingleInterRetarget(inter_bone,performer_bones_s) else: perf_bone = performer_bones[perf_bone_name[0]] + locOfOriginal(inter_bone,perf_bone) inter_bone.matrix_basis = singleBoneRetarget(inter_bone,perf_bone) inter_bone.keyframe_insert("rotation_quaternion") @@ -121,6 +136,8 @@ def createIntermediate(): #resets roll bpy.ops.armature.calculate_roll(type='Z') bpy.ops.object.mode_set(mode="OBJECT") + inter_arm = bpy.data.armatures["enduser_arm.001"] + inter_arm.name = "inter_arm" performer_bones = performer_obj.pose.bones inter_bones = inter_obj.pose.bones @@ -132,5 +149,50 @@ def createIntermediate(): scene.frame_set(t) inter_bone = inter_bones["DEF_Hip"] retargetPerfToInter(inter_bone) - -createIntermediate() \ No newline at end of file + + return inter_obj,inter_arm + +# this procedure copies the rotations over from the intermediate +# armature to the end user one. +# As the hierarchies are 1 to 1, this is a simple matter of +# copying the rotation, while keeping in mind bone roll, parenting, etc. +# TODO: Control Bones: If a certain bone is constrained in a way +# that its rotation is determined by another (a control bone) +# We should determine the right pos of the control bone. +# Scale: ? Should work but needs testing. +def retargetEnduser(): + inter_bones = inter_obj.pose.bones + end_bones = enduser_obj.pose.bones + + def bakeTransform(end_bone): + src_bone = inter_bones[end_bone.name] + trg_bone = end_bone + bake_matrix = src_bone.matrix + rest_matrix = trg_bone.bone.matrix_local + + if trg_bone.parent and trg_bone.bone.use_inherit_rotation: + parent_mat = src_bone.parent.matrix + parent_rest = trg_bone.parent.bone.matrix_local + parent_rest_inv = parent_rest.copy() + parent_rest_inv.invert() + parent_mat_inv = parent_mat.copy() + parent_mat_inv.invert() + bake_matrix = parent_mat_inv * bake_matrix + rest_matrix = parent_rest_inv * rest_matrix + + rest_matrix_inv = rest_matrix.copy() + rest_matrix_inv.invert() + bake_matrix = rest_matrix_inv * bake_matrix + trg_bone.matrix_basis = bake_matrix + end_bone.keyframe_insert("rotation_quaternion") + + for bone in end_bone.children: + bakeTransform(bone) + + for t in range(1,150): + scene.frame_set(t) + end_bone = end_bones["DEF_Hip"] + bakeTransform(end_bone) + +inter_obj, inter_arm = createIntermediate() +retargetEnduser() \ No newline at end of file -- cgit v1.2.3 From f4b2e9b91d78b270f8741cec9b8770579d424f4a Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 10 Jun 2011 12:43:06 +0000 Subject: Added operator to make importing Keying Sets from files easier. This can be found from the dropdown below the Add/Remove buttons in the Properties Editor -> Scene -> Keying Sets panel. --- release/scripts/startup/bl_ui/properties_scene.py | 39 +++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py index 7725f661693..e2dc9de064f 100644 --- a/release/scripts/startup/bl_ui/properties_scene.py +++ b/release/scripts/startup/bl_ui/properties_scene.py @@ -76,6 +76,7 @@ class SCENE_PT_keying_sets(SceneButtonsPanel, bpy.types.Panel): col = row.column(align=True) col.operator("anim.keying_set_add", icon='ZOOMIN', text="") col.operator("anim.keying_set_remove", icon='ZOOMOUT', text="") + col.menu("SCENE_MT_keying_set_specials", icon='DOWNARROW_HLT', text="") ks = scene.keying_sets.active if ks and ks.is_path_absolute: @@ -94,6 +95,14 @@ class SCENE_PT_keying_sets(SceneButtonsPanel, bpy.types.Panel): col.prop(ks, "bl_options") +class SCENE_MT_keying_set_specials(bpy.types.Menu): + bl_label = "Keying Set Specials" + + def draw(self, context): + layout = self.layout + + layout.operator("anim.keying_set_import", text="Import From File") + class SCENE_PT_keying_set_paths(SceneButtonsPanel, bpy.types.Panel): bl_label = "Active Keying Set" @@ -198,6 +207,36 @@ class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, bpy.types.Panel): # XXX, move operator to op/ dir +class ANIM_OT_keying_set_import(bpy.types.Operator): + "Import Keying Set from a python script." + bl_idname = "anim.keying_set_import" + bl_label = "Import Keying Set from File" + + filepath = bpy.props.StringProperty(name="File Path", description="Filepath to read file from.") + filter_folder = bpy.props.BoolProperty(name="Filter folders", description="", default=True, options={'HIDDEN'}) + filter_text = bpy.props.BoolProperty(name="Filter text", description="", default=True, options={'HIDDEN'}) + filter_python = bpy.props.BoolProperty(name="Filter python", description="", default=True, options={'HIDDEN'}) + + def execute(self, context): + if not self.filepath: + raise Exception("Filepath not set.") + + f = open(self.filepath, "r") + if not f: + raise Exception("Could not open file.") + + # lazy way of loading and running this file... + exec(compile(f.read(), self.filepath, 'exec')) + + f.close() + + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.window_manager + wm.fileselect_add(self) + return {'RUNNING_MODAL'} + class ANIM_OT_keying_set_export(bpy.types.Operator): "Export Keying Set to a python script." bl_idname = "anim.keying_set_export" -- cgit v1.2.3 From cfcc4b4fcd7dabd0929db53fc5a9cf0833704259 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 16 Jun 2011 02:46:38 +0000 Subject: == Simple Title Cards for Sequencer == This commit adds an experimental effect strip to the sequencer: "Title Card". This is useful for adding simple one-line text section headers or "title cards" (i.e. title + author/contact details) to video clips, which is often seen in demo videos accompanying papers and/or animation tests. See http://aligorith.blogspot.com/2011/06/gsoc11-simple-title- cards.html for some more details on usage. Code notes: - There are a few things I've done here which will probably need cleaning up. For instance, the hacks to get threadsafe fonts for rendering, and also the way I've tried to piggyback the backdrop drawing on top of the Solid Colour strips (this method was used to keep changes here minimal, but is quite fragile if things change). --- release/scripts/startup/bl_ui/space_sequencer.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index c477a2ff62b..6a2f2f3a301 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -214,6 +214,7 @@ class SEQUENCER_MT_add_effect(bpy.types.Menu): layout.operator("sequencer.effect_strip_add", text="Speed Control").type = 'SPEED' layout.operator("sequencer.effect_strip_add", text="Multicam Selector").type = 'MULTICAM' layout.operator("sequencer.effect_strip_add", text="Adjustment Layer").type = 'ADJUSTMENT' + layout.operator("sequencer.effect_strip_add", text="Title Card").type = 'TITLE_CARD' class SEQUENCER_MT_strip(bpy.types.Menu): @@ -392,7 +393,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, bpy.types.Panel): 'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP', 'PLUGIN', 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', 'SPEED', - 'MULTICAM', 'ADJUSTMENT'} + 'MULTICAM', 'ADJUSTMENT', 'TITLE_CARD'} def draw(self, context): layout = self.layout @@ -460,6 +461,11 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, bpy.types.Panel): row.label("Cut To") for i in range(1, strip.channel): row.operator("sequencer.cut_multicam", text=str(i)).camera = i + elif strip.type == "TITLE_CARD": + layout.prop(strip, "title") + layout.prop(strip, "subtitle") + layout.prop(strip, "color_foreground") + layout.prop(strip, "color_background") col = layout.column(align=True) if strip.type == 'SPEED': @@ -531,7 +537,8 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, bpy.types.Panel): 'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP', 'PLUGIN', 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', - 'MULTICAM', 'SPEED', 'ADJUSTMENT'} + 'MULTICAM', 'SPEED', 'ADJUSTMENT', + 'TITLE_CARD'} def draw(self, context): layout = self.layout @@ -687,7 +694,8 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, bpy.types.Panel): 'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP', 'PLUGIN', 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', - 'MULTICAM', 'SPEED', 'ADJUSTMENT'} + 'MULTICAM', 'SPEED', 'ADJUSTMENT', + 'TITLE_CARD'} def draw(self, context): layout = self.layout -- cgit v1.2.3 From c9360a4c1e30328a4a85a7b39fb897aacb9fe262 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Fri, 17 Jun 2011 11:47:45 +0000 Subject: Added calculation to determine change in root translation when retargeting - needs cleanup/optimization --- release/scripts/modules/retarget.py | 124 +++++++++++++++++++++++++++++------- 1 file changed, 100 insertions(+), 24 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index b081191d9a6..b38e47a63ff 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -15,27 +15,35 @@ scene = bpy.context.scene # dictionary of mapping # this is currently manuall input'ed, but will # be created from a more comfortable UI in the future -bonemap = { "LeftFoot": ("DEF_Foot.L","DEF_Toes.L"), - "LeftUpLeg": "DEF_Thigh.L", - "Hips": "DEF_Hip", - "LowerBack": "DEF_Spine", - "Spine": "DEF_Torso", - "Neck": "DEF_Neck", - "Neck1": "DEF_Neck", - "Head": "DEF_Head", - "LeftShoulder": "DEF_Shoulder.L", - "LeftArm": "DEF_Forearm.L", - "LeftForeArm": "DEF_Arm.L", - "LeftHand": "DEF_Hand.L", - "RightShoulder": "DEF_Shoulder.R", - "RightArm": "DEF_Forearm.R", - "RightForeArm": "DEF_Arm.R", - "RightHand": "DEF_Hand.R", - "RightFoot": ("DEF_Foot.R","DEF_Toes.R"), - "RightUpLeg": "DEF_Thigh.R", - "RightLeg": "DEF_Shin.R", - "LeftLeg": "DEF_Shin.L"} +bonemap = { "Head": "Head", + "Neck": "Head", + "Spine1": "Chest", + "Spine2": "Chest", + "Spine3": "Chest", + "Spine": "Torso", + "Hips": "root", + "LeftUpLeg": "Thigh.L", + "LeftUpLegRoll": "Thigh.L", + "LeftLeg": "Shin.L", + "LeftLegRoll": "Shin.L", + "LeftFoot": "Foot.L", + "RightUpLeg": "Thigh.R", + "RightUpLegRoll": "Thigh.R", + "RightLeg": "Shin.R", + "RightLegRoll": "Shin.R", + "RightFoot": "Foot.R", + "LeftShoulder": "Shoulder.L", + "LeftArm": "HiArm.L", + "LeftArmRoll": "HiArm.L", + "LeftForeArm": "LoArm.L", + "LeftForeArmRoll": "LoArm.L", + "RightShoulder": "Shoulder.R", + "RightArm": "HiArm.R", + "RightArmRoll": "HiArm.R", + "RightForeArm": "LoArm.R", + "RightForeArmRoll": "LoArm.R" } +root = "root" # creation of a reverse map # multiple keys get mapped to list values bonemapr = {} @@ -76,7 +84,10 @@ def createIntermediate(): empty.name = perf_bone.name+"Org" empty = bpy.data.objects[perf_bone.name+"Org"] offset = perf_bone.vector - scaling = perf_bone.length / inter_bone.length + if inter_bone.length == 0 or perf_bone.length == 0: + scaling = 1 + else: + scaling = perf_bone.length / inter_bone.length offset/=scaling empty.location = inter_bone.head + offset empty.keyframe_insert("location") @@ -147,7 +158,7 @@ def createIntermediate(): for t in range(1,150): scene.frame_set(t) - inter_bone = inter_bones["DEF_Hip"] + inter_bone = inter_bones[root] retargetPerfToInter(inter_bone) return inter_obj,inter_arm @@ -191,8 +202,73 @@ def retargetEnduser(): for t in range(1,150): scene.frame_set(t) - end_bone = end_bones["DEF_Hip"] + end_bone = end_bones[root] bakeTransform(end_bone) +#recieves the performer feet bones as a variable +# by "feet" I mean those bones that have plants +# (they don't move, despite root moving) somewhere in the animation. +def copyTranslation(perfFeet): + endFeet = [bonemap[perfBone] for perfBone in perfFeet] + perfRoot = bonemapr[root][0] + locDictKeys = perfFeet+endFeet+[perfRoot] + perf_bones = performer_obj.pose.bones + end_bones = enduser_obj.pose.bones + + def tailLoc(bone): + return bone.center+(bone.vector/2) + + #Step 1 - we create a dict that contains these keys: + #(Performer) Hips, Feet + #(End user) Feet + # where the values are their world position on each (1,120) frame + + locDict = {} + for key in locDictKeys: + locDict[key] = [] + + for t in range(scene.frame_start,scene.frame_end): + scene.frame_set(t) + for bone in perfFeet: + locDict[bone].append(tailLoc(perf_bones[bone])) + locDict[perfRoot].append(tailLoc(perf_bones[perfRoot])) + for bone in endFeet: + locDict[bone].append(tailLoc(end_bones[bone])) + + # now we take our locDict and analyze it. + # we need to derive all chains + + locDeriv = {} + for key in locDictKeys: + locDeriv[key] = [] + + for key in locDict.keys(): + graph = locDict[key] + for t in range(len(graph)-1): + x = graph[t] + xh = graph[t+1] + locDeriv[key].append(xh-x) + + # now find the plant frames, where perfFeet don't move much + + linearAvg = [] + + for key in perfFeet: + for i in range(len(locDeriv[key])-1): + v = locDeriv[key][i] + hipV = locDeriv[perfRoot][i] + endV = locDeriv[bonemap[key]][i] + if (v.length<0.1): + #this is a plant frame. + #lets see what the original hip delta is, and the corresponding + #end bone's delta + if endV.length!=0: + linearAvg.append(hipV.length/endV.length) + if linearAvg: + avg = sum(linearAvg)/len(linearAvg) + print("retargeted root motion should be "+ str(1/avg)+ " of original") + + inter_obj, inter_arm = createIntermediate() -retargetEnduser() \ No newline at end of file +retargetEnduser() +copyTranslation(["RightFoot","LeftFoot"]) \ No newline at end of file -- cgit v1.2.3 From 2d3d025e8cf8776361e6397502f4e240ae9a5ccc Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Tue, 21 Jun 2011 20:39:41 +0000 Subject: 3D Audio GSoC: - Sequencer dynamics: Now it's possible to change the output channels and the resampling quality also increased (previously maximum quality was 44,1 kHz) - Changed two buffers to use ffmpeg allocation, not sure if that helps somehow. --- release/scripts/presets/ffmpeg/DV.py | 1 + release/scripts/presets/ffmpeg/DVD.py | 1 + release/scripts/presets/ffmpeg/SVCD.py | 1 + release/scripts/presets/ffmpeg/VCD.py | 1 + release/scripts/startup/bl_ui/properties_render.py | 4 +++- 5 files changed, 7 insertions(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/presets/ffmpeg/DV.py b/release/scripts/presets/ffmpeg/DV.py index 46d2a0a4a2f..926fb241747 100644 --- a/release/scripts/presets/ffmpeg/DV.py +++ b/release/scripts/presets/ffmpeg/DV.py @@ -11,3 +11,4 @@ else: bpy.context.scene.render.ffmpeg_audio_mixrate = 48000 bpy.context.scene.render.ffmpeg_audio_codec = "PCM" +bpy.context.scene.render.ffmpeg_audio_channels = 2 diff --git a/release/scripts/presets/ffmpeg/DVD.py b/release/scripts/presets/ffmpeg/DVD.py index e18ec9f817b..196b5d68406 100644 --- a/release/scripts/presets/ffmpeg/DVD.py +++ b/release/scripts/presets/ffmpeg/DVD.py @@ -21,3 +21,4 @@ bpy.context.scene.render.ffmpeg_muxrate = 10080000 bpy.context.scene.render.ffmpeg_audio_codec = "AC3" bpy.context.scene.render.ffmpeg_audio_bitrate = 448 bpy.context.scene.render.ffmpeg_audio_mixrate = 48000 +bpy.context.scene.render.ffmpeg_audio_channels = 6 diff --git a/release/scripts/presets/ffmpeg/SVCD.py b/release/scripts/presets/ffmpeg/SVCD.py index c71a3851af0..e4459ab5c5c 100644 --- a/release/scripts/presets/ffmpeg/SVCD.py +++ b/release/scripts/presets/ffmpeg/SVCD.py @@ -21,3 +21,4 @@ bpy.context.scene.render.ffmpeg_muxrate = 0 bpy.context.scene.render.ffmpeg_audio_bitrate = 224 bpy.context.scene.render.ffmpeg_audio_mixrate = 44100 bpy.context.scene.render.ffmpeg_audio_codec = "MP2" +bpy.context.scene.render.ffmpeg_audio_channels = 2 diff --git a/release/scripts/presets/ffmpeg/VCD.py b/release/scripts/presets/ffmpeg/VCD.py index faf27efe9e6..c2b73e682a2 100644 --- a/release/scripts/presets/ffmpeg/VCD.py +++ b/release/scripts/presets/ffmpeg/VCD.py @@ -21,3 +21,4 @@ bpy.context.scene.render.ffmpeg_muxrate = 2352 * 75 * 8 bpy.context.scene.render.ffmpeg_audio_bitrate = 224 bpy.context.scene.render.ffmpeg_audio_mixrate = 44100 bpy.context.scene.render.ffmpeg_audio_codec = "MP2" +bpy.context.scene.render.ffmpeg_audio_channels = 2 diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index 54ca18ef828..9ff4470641b 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -596,7 +596,9 @@ class RENDER_PT_encoding(RenderButtonsPanel, bpy.types.Panel): col.prop(rd, "ffmpeg_audio_bitrate") col.prop(rd, "ffmpeg_audio_mixrate") - split.prop(rd, "ffmpeg_audio_volume", slider=True) + col = split.column() + col.prop(rd, "ffmpeg_audio_volume", slider=True) + col.prop(rd, "ffmpeg_audio_channels") class RENDER_PT_bake(RenderButtonsPanel, bpy.types.Panel): -- cgit v1.2.3 From b437f3fab9f2e790c14dfdfe828aa648c871a8b1 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Fri, 24 Jun 2011 17:05:53 +0000 Subject: UI and bugfixing for mocap retargeting. Still a WIP, UI/py work will modified to fit coding styles in the future. --- release/scripts/startup/ui_mocap.py | 97 +++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 release/scripts/startup/ui_mocap.py (limited to 'release') diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py new file mode 100644 index 00000000000..5f59c368393 --- /dev/null +++ b/release/scripts/startup/ui_mocap.py @@ -0,0 +1,97 @@ +import bpy +import time + +from bpy.props import * +from bpy import * +from mathutils import Vector +from math import isfinite + +bpy.types.Scene.performer = bpy.props.StringProperty() +bpy.types.Scene.enduser = bpy.props.StringProperty() + +bpy.types.Bone.map = bpy.props.StringProperty() +import retarget +import mocap_tools + +class MocapPanel(bpy.types.Panel): + bl_label = "Mocap tools" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "object" + + def draw(self, context): + self.layout.label("Preprocessing") + row = self.layout.row(align=True) + row.alignment = 'EXPAND' + row.operator("mocap.samples", text='Samples to Beziers') + row.operator("mocap.denoise", text='Clean noise') + row2 = self.layout.row(align=True) + row2.operator("mocap.looper", text='Loop animation') + row2.operator("mocap.limitdof", text='Constrain Rig') + self.layout.label("Retargeting") + row3 = self.layout.row(align=True) + column1 = row3.column(align=True) + column1.label("Performer Rig") + column1.prop_search(context.scene, "performer", context.scene, "objects") + column2 = row3.column(align=True) + column2.label("Enduser Rig") + column2.prop_search(context.scene, "enduser", context.scene, "objects") + self.layout.label("Hierarchy mapping") + if context.scene.performer in bpy.data.armatures and context.scene.enduser in bpy.data.armatures: + perf = bpy.data.armatures[context.scene.performer] + enduser_arm = bpy.data.armatures[context.scene.enduser] + for bone in perf.bones: + row = self.layout.row(align=True) + row.label(bone.name) + row.prop_search(bone, "map", enduser_arm, "bones") + self.layout.operator("mocap.retarget", text='RETARGET!') + + + + +class OBJECT_OT_RetargetButton(bpy.types.Operator): + bl_idname = "mocap.retarget" + bl_label = "Retargets active action from Performer to Enduser" + + def execute(self, context): + retarget.totalRetarget() + return {"FINISHED"} + +class OBJECT_OT_ConvertSamplesButton(bpy.types.Operator): + bl_idname = "mocap.samples" + bl_label = "Converts samples / simplifies keyframes to beziers" + + def execute(self, context): + mocap_tools.fcurves_simplify() + return {"FINISHED"} + +class OBJECT_OT_LooperButton(bpy.types.Operator): + bl_idname = "mocap.looper" + bl_label = "loops animation / sampled mocap data" + + def execute(self, context): + mocap_tools.autoloop_anim() + return {"FINISHED"} + +class OBJECT_OT_DenoiseButton(bpy.types.Operator): + bl_idname = "mocap.denoise" + bl_label = "Denoises sampled mocap data " + + def execute(self, context): + return {"FINISHED"} + +class OBJECT_OT_LimitDOFButton(bpy.types.Operator): + bl_idname = "mocap.limitdof" + bl_label = "Analyzes animations Max/Min DOF and adds hard/soft constraints" + + def execute(self, context): + return {"FINISHED"} + +def register(): + bpy.utils.register_module(__name__) + +def unregister(): + bpy.utils.unregister_module(__name__) + +if __name__=="__main__": + register() -- cgit v1.2.3 From 5663d85e563f3d6cba8c08982b7899bb2569411f Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Sat, 25 Jun 2011 23:50:50 +0000 Subject: Some bugfixing and coding styles changes suggested by ideasman_42. --- release/scripts/modules/mocap_tools.py | 550 ++++++++++++++++++--------------- release/scripts/modules/retarget.py | 264 +++++++++------- release/scripts/startup/ui_mocap.py | 88 ++++-- 3 files changed, 511 insertions(+), 391 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index 739dc40b272..dfb8aaf0eec 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -1,62 +1,107 @@ +# ##### 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 ##### + +# + from math import hypot, sqrt, isfinite import bpy import time from mathutils import Vector + #Vector utility functions class NdVector: vec = [] - - def __init__(self,vec): + + def __init__(self, vec): self.vec = vec[:] - + def __len__(self): return len(self.vec) - - def __mul__(self,otherMember): - if type(otherMember)==type(1) or type(otherMember)==type(1.0): - return NdVector([otherMember*x for x in self.vec]) + + def __mul__(self, otherMember): + if (isinstance(otherMember, int) or + isinstance(otherMember, float)): + return NdVector([otherMember * x for x in self.vec]) else: a = self.vec b = otherMember.vec n = len(self) - return sum([a[i]*b[i] for i in range(n)]) - - def __sub__(self,otherVec): + return sum([a[i] * b[i] for i in range(n)]) + + def __sub__(self, otherVec): a = self.vec b = otherVec.vec n = len(self) - return NdVector([a[i]-b[i] for i in range(n)]) - - def __add__(self,otherVec): + return NdVector([a[i] - b[i] for i in range(n)]) + + def __add__(self, otherVec): a = self.vec b = otherVec.vec n = len(self) - return NdVector([a[i]+b[i] for i in range(n)]) - + return NdVector([a[i] + b[i] for i in range(n)]) + + def __div__(self, scalar): + return NdVector([x / scalar for x in self.vec]) + def vecLength(self): return sqrt(self * self) - + def vecLengthSq(self): return (self * self) - - def __getitem__(self,i): + + def normalize(self): + len = self.length + self.vec = [x / len for x in self.vec] + + def copy(self): + return NdVector(self.vec) + + def __getitem__(self, i): return self.vec[i] - + + def x(self): + return self.vec[0] + + def y(self): + return self.vec[1] + length = property(vecLength) lengthSq = property(vecLengthSq) + x = property(x) + y = property(y) + class dataPoint: index = 0 - co = Vector((0,0,0,0)) # x,y1,y2,y3 coordinate of original point - u = 0 #position according to parametric view of original data, [0,1] range - temp = 0 #use this for anything - - def __init__(self,index,co,u=0): + # x,y1,y2,y3 coordinate of original point + co = NdVector((0, 0, 0, 0, 0)) + #position according to parametric view of original data, [0,1] range + u = 0 + #use this for anything + temp = 0 + + def __init__(self, index, co, u=0): self.index = index self.co = co self.u = u + def autoloop_anim(): context = bpy.context obj = context.active_object @@ -64,388 +109,407 @@ def autoloop_anim(): data = [] end = len(fcurves[0].keyframe_points) - - for i in range(1,end): + + for i in range(1, end): vec = [] for fcurve in fcurves: vec.append(fcurve.evaluate(i)) data.append(NdVector(vec)) - - def comp(a,b): - return a*b - + + def comp(a, b): + return a * b + N = len(data) Rxy = [0.0] * N for i in range(N): - for j in range(i,min(i+N,N)): - Rxy[i]+=comp(data[j],data[j-i]) + for j in range(i, min(i + N, N)): + Rxy[i] += comp(data[j], data[j - i]) for j in range(i): - Rxy[i]+=comp(data[j],data[j-i+N]) - Rxy[i]/=float(N) - + Rxy[i] += comp(data[j], data[j - i + N]) + Rxy[i] /= float(N) + def bestLocalMaximum(Rxy): - Rxyd = [Rxy[i]-Rxy[i-1] for i in range(1,len(Rxy))] + Rxyd = [Rxy[i] - Rxy[i - 1] for i in range(1, len(Rxy))] maxs = [] - for i in range(1,len(Rxyd)-1): - a = Rxyd[i-1] + for i in range(1, len(Rxyd) - 1): + a = Rxyd[i - 1] b = Rxyd[i] - print(a,b) - if (a>=0 and b<0) or (a<0 and b>=0): #sign change (zerocrossing) at point i, denoting max point (only) - maxs.append((i,max(Rxy[i],Rxy[i-1]))) - return max(maxs,key=lambda x: x[1])[0] + print(a, b) + #sign change (zerocrossing) at point i, denoting max point (only) + if (a >= 0 and b < 0) or (a < 0 and b >= 0): + maxs.append((i, max(Rxy[i], Rxy[i - 1]))) + return max(maxs, key=lambda x: x[1])[0] flm = bestLocalMaximum(Rxy[0:int(len(Rxy))]) - + diff = [] - - for i in range(len(data)-flm): - diff.append((data[i]-data[i+flm]).lengthSq) - - def lowerErrorSlice(diff,e): - bestSlice = (0,100000) #index, error at index - for i in range(e,len(diff)-e): - errorSlice = sum(diff[i-e:i+e+1]) - if errorSlice= maxError: maxError = tmpError maxErrorPt = pt.index - return maxError,maxErrorPt - + return maxError, maxErrorPt #calculated bezier derivative at point t. #That is, tangent of point t. - def getBezDerivative(bez,t): - n = len(bez)-1 - sumVec = Vector((0,0,0,0)) - for i in range(n-1): - sumVec+=bernsteinPoly(n-1,i,t)*(bez[i+1]-bez[i]) + def getBezDerivative(bez, t): + n = len(bez) - 1 + sumVec = NdVector((0, 0, 0, 0, 0)) + for i in range(n - 1): + sumVec += (bez[i + 1] - bez[i]) * bernsteinPoly(n - 1, i, t) return sumVec - - + #use Newton-Raphson to find a better paramterization of datapoints, - #one that minimizes the distance (or error) between bezier and original data. - def newtonRaphson(data_pts,s,e,bez): - for pt in data_pts[s:e+1]: - if pt.index==s: - pt.u=0 - elif pt.index==e: - pt.u=1 + #one that minimizes the distance (or error) + # between bezier and original data. + def newtonRaphson(data_pts, s, e, bez): + for pt in data_pts[s:e + 1]: + if pt.index == s: + pt.u = 0 + elif pt.index == e: + pt.u = 1 else: u = pt.u - qu = bezierEval(bez,pt.u) - qud = getBezDerivative(bez,u) - #we wish to minimize f(u), the squared distance between curve and data - fu = (qu-pt.co).length**2 - fud = (2*(qu.x-pt.co.x)*(qud.x))-(2*(qu.y-pt.co.y)*(qud.y)) - if fud==0: + qu = bezierEval(bez, pt.u) + qud = getBezDerivative(bez, u) + #we wish to minimize f(u), + #the squared distance between curve and data + fu = (qu - pt.co).length ** 2 + fud = (2 * (qu.x - pt.co.x) * (qud.x)) - (2 * (qu.y - pt.co.y) * (qud.y)) + if fud == 0: fu = 0 fud = 1 - pt.u=pt.u-(fu/fud) + pt.u = pt.u - (fu / fud) def createDataPts(curveGroup, group_mode): data_pts = [] if group_mode: + print([x.data_path for x in curveGroup]) for i in range(len(curveGroup[0].keyframe_points)): x = curveGroup[0].keyframe_points[i].co.x y1 = curveGroup[0].keyframe_points[i].co.y y2 = curveGroup[1].keyframe_points[i].co.y y3 = curveGroup[2].keyframe_points[i].co.y - data_pts.append(dataPoint(i,Vector((x,y1,y2,y3)))) + y4 = 0 + if len(curveGroup) == 4: + y4 = curveGroup[3].keyframe_points[i].co.y + data_pts.append(dataPoint(i, NdVector((x, y1, y2, y3, y4)))) else: for i in range(len(curveGroup.keyframe_points)): x = curveGroup.keyframe_points[i].co.x y1 = curveGroup.keyframe_points[i].co.y y2 = 0 y3 = 0 - data_pts.append(dataPoint(i,Vector((x,y1,y2,y3)))) + y4 = 0 + data_pts.append(dataPoint(i, NdVector((x, y1, y2, y3, y4)))) return data_pts - def fitCubic(data_pts,s,e): - - if e-s<3: # if there are less than 3 points, fit a single basic bezier - bez = fitSingleCubic2Pts(data_pts,s,e) + def fitCubic(data_pts, s, e): + # if there are less than 3 points, fit a single basic bezier + if e - s < 3: + bez = fitSingleCubic2Pts(data_pts, s, e) else: - #if there are more, parameterize the points and fit a single cubic bezier - chordLength(data_pts,s,e) - bez = fitSingleCubic(data_pts,s,e) - + #if there are more, parameterize the points + # and fit a single cubic bezier + chordLength(data_pts, s, e) + bez = fitSingleCubic(data_pts, s, e) + #calculate max error and point where it occurs - maxError,maxErrorPt = maxErrorAmount(data_pts,bez,s,e) + maxError, maxErrorPt = maxErrorAmount(data_pts, bez, s, e) #if error is small enough, reparameterization might be enough - if maxErrorerror: + if maxError < reparaError and maxError > error: for i in range(maxIterations): - newtonRaphson(data_pts,s,e,bez) - if e-s<3: - bez = fitSingleCubic2Pts(data_pts,s,e) + newtonRaphson(data_pts, s, e, bez) + if e - s < 3: + bez = fitSingleCubic2Pts(data_pts, s, e) else: - bez = fitSingleCubic(data_pts,s,e) - + bez = fitSingleCubic(data_pts, s, e) #recalculate max error and point where it occurs - maxError,maxErrorPt = maxErrorAmount(data_pts,bez,s,e) - + maxError, maxErrorPt = maxErrorAmount(data_pts, bez, s, e) + #repara wasn't enough, we need 2 beziers for this range. #Split the bezier at point of maximum error - if maxError>error: - fitCubic(data_pts,s,maxErrorPt) - fitCubic(data_pts,maxErrorPt,e) + if maxError > error: + fitCubic(data_pts, s, maxErrorPt) + fitCubic(data_pts, maxErrorPt, e) else: #error is small enough, return the beziers. beziers.append(bez) return - def createNewCurves(curveGroup,beziers,group_mode): + def createNewCurves(curveGroup, beziers, group_mode): #remove all existing data points if group_mode: for fcurve in curveGroup: - for i in range(len(fcurve.keyframe_points)-1,0,-1): + for i in range(len(fcurve.keyframe_points) - 1, 0, -1): fcurve.keyframe_points.remove(fcurve.keyframe_points[i]) else: fcurve = curveGroup - for i in range(len(fcurve.keyframe_points)-1,0,-1): + for i in range(len(fcurve.keyframe_points) - 1, 0, -1): fcurve.keyframe_points.remove(fcurve.keyframe_points[i]) - + #insert the calculated beziers to blender data.\ - if group_mode: + if group_mode: for fullbez in beziers: - for i,fcurve in enumerate(curveGroup): - bez = [Vector((vec[0],vec[i+1])) for vec in fullbez] - newKey = fcurve.keyframe_points.insert(frame=bez[0].x,value=bez[0].y) - newKey.handle_right = (bez[1].x,bez[1].y) - - newKey = fcurve.keyframe_points.insert(frame=bez[3].x,value=bez[3].y) - newKey.handle_left= (bez[2].x,bez[2].y) + for i, fcurve in enumerate(curveGroup): + bez = [Vector((vec[0], vec[i + 1])) for vec in fullbez] + newKey = fcurve.keyframe_points.insert(frame=bez[0].x, value=bez[0].y) + newKey.handle_right = (bez[1].x, bez[1].y) + + newKey = fcurve.keyframe_points.insert(frame=bez[3].x, value=bez[3].y) + newKey.handle_left = (bez[2].x, bez[2].y) else: for bez in beziers: for vec in bez: vec.resize_2d() - newKey = fcurve.keyframe_points.insert(frame=bez[0].x,value=bez[0].y) - newKey.handle_right = (bez[1].x,bez[1].y) - - newKey = fcurve.keyframe_points.insert(frame=bez[3].x,value=bez[3].y) - newKey.handle_left= (bez[2].x,bez[2].y) - - #indices are detached from data point's frame (x) value and stored in the dataPoint object, represent a range - - data_pts = createDataPts(curveGroup,group_mode) - - s = 0 #start - e = len(data_pts)-1 #end - + newKey = fcurve.keyframe_points.insert(frame=bez[0].x, value=bez[0].y) + newKey.handle_right = (bez[1].x, bez[1].y) + + newKey = fcurve.keyframe_points.insert(frame=bez[3].x, value=bez[3].y) + newKey.handle_left = (bez[2].x, bez[2].y) + + # indices are detached from data point's frame (x) value and + # stored in the dataPoint object, represent a range + + data_pts = createDataPts(curveGroup, group_mode) + + s = 0 # start + e = len(data_pts) - 1 # end + beziers = [] - #begin the recursive fitting algorithm. - fitCubic(data_pts,s,e) + #begin the recursive fitting algorithm. + fitCubic(data_pts, s, e) #remove old Fcurves and insert the new ones - createNewCurves(curveGroup,beziers,group_mode) - + createNewCurves(curveGroup, beziers, group_mode) + #Main function of simplification #sel_opt: either "sel" or "all" for which curves to effect -#error: maximum error allowed, in fraction (20% = 0.0020), i.e. divide by 10000 from percentage wanted. -#group_mode: boolean, to analyze each curve seperately or in groups, where group is all curves that effect the same property (e.g. a bone's x,y,z rotation) +#error: maximum error allowed, in fraction (20% = 0.0020), +#i.e. divide by 10000 from percentage wanted. +#group_mode: boolean, to analyze each curve seperately or in groups, +#where group is all curves that effect the same property +#(e.g. a bone's x,y,z rotation) + def fcurves_simplify(sel_opt="all", error=0.002, group_mode=True): # main vars context = bpy.context obj = context.active_object fcurves = obj.animation_data.action.fcurves - - if sel_opt=="sel": + + if sel_opt == "sel": sel_fcurves = [fcurve for fcurve in fcurves if fcurve.select] else: sel_fcurves = fcurves[:] #Error threshold for Newton Raphson reparamatizing - reparaError = error*32 + reparaError = error * 32 maxIterations = 16 - + if group_mode: fcurveDict = {} - #this loop sorts all the fcurves into groups of 3, based on their RNA Data path, which corresponds to which property they effect + #this loop sorts all the fcurves into groups of 3 or 4, + #based on their RNA Data path, which corresponds to + #which property they effect for curve in sel_fcurves: - if curve.data_path in fcurveDict: #if this bone has been added, append the curve to its list + if curve.data_path in fcurveDict: # if this bone has been added, append the curve to its list fcurveDict[curve.data_path].append(curve) else: - fcurveDict[curve.data_path] = [curve] #new bone, add a new dict value with this first curve + fcurveDict[curve.data_path] = [curve] # new bone, add a new dict value with this first curve fcurveGroups = fcurveDict.values() else: fcurveGroups = sel_fcurves - - if error>0.00000: + + if error > 0.00000: #simplify every selected curve. totalt = 0 - for i,fcurveGroup in enumerate(fcurveGroups): - print("Processing curve "+str(i+1)+"/"+str(len(fcurveGroups))) + for i, fcurveGroup in enumerate(fcurveGroups): + print("Processing curve " + str(i + 1) + "/" + str(len(fcurveGroups))) t = time.clock() - simplifyCurves(fcurveGroup,error,reparaError,maxIterations,group_mode) + simplifyCurves(fcurveGroup, error, reparaError, maxIterations, group_mode) t = time.clock() - t - print(str(t)[:5]+" seconds to process last curve") - totalt+=t - print(str(totalt)[:5]+" seconds, total time elapsed") - - return + print(str(t)[:5] + " seconds to process last curve") + totalt += t + print(str(totalt)[:5] + " seconds, total time elapsed") + return diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 642ea5b6e31..8fe8c6937bb 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -1,37 +1,57 @@ +# ##### 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 ##### + +# + import bpy from mathutils import * from math import radians, acos #TODO: Only selected bones get retargeted. -# Selected Bones/chains get original pos empties, if ppl want IK instead of FK -# Some "magic" numbers - frame start and end, eulers of all orders instead of just quats keyframed +# Selected Bones/chains get original pos empties, +# if ppl want IK instead of FK +# Some "magic" numbers - frame start and end, +# eulers of all orders instead of just quats keyframed # dictionary of mapping -# this is currently manuall input'ed, but will +# this is currently manuall input'ed, but willW # be created from a more comfortable UI in the future + def createDictionary(perf_arm): bonemap = {} - #perf: enduser for bone in perf_arm.bones: bonemap[bone.name] = bone.map - #root is the root of the enduser root = "root" # creation of a reverse map # multiple keys get mapped to list values bonemapr = {} - for key in bonemap.keys(): - if not bonemap[key] in bonemapr: - if type(bonemap[key])==type((0,0)): + for key, value in bonemap.items(): + if not value in bonemapr: + if isinstance(bonemap[key], tuple): for key_x in bonemap[key]: bonemapr[key_x] = [key] else: bonemapr[bonemap[key]] = [key] else: bonemapr[bonemap[key]].append(key) - - return bonemap, bonemapr, root + return bonemap, bonemapr, root # list of empties created to keep track of "original" # position data # in final product, these locations can be stored as custom props @@ -43,118 +63,120 @@ def createDictionary(perf_arm): # and bone roll is identical to the performer # its purpose is to copy over the rotations # easily while concentrating on the hierarchy changes -def createIntermediate(performer_obj,endu_name,bonemap, bonemapr,root,s_frame,e_frame,scene): - + + +def createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_frame, e_frame, scene): #creates and keyframes an empty with its location #the original position of the tail bone #useful for storing the important data in the original motion #i.e. using this empty to IK the chain to that pos / DEBUG - def locOfOriginal(inter_bone,perf_bone): - pass -# if not perf_bone.name+"Org" in bpy.data.objects: -# bpy.ops.object.add() -# empty = bpy.context.active_object -# empty.name = perf_bone.name+"Org" -# empty.empty_draw_size = 0.01 -# empty = bpy.data.objects[perf_bone.name+"Org"] -# offset = perf_bone.vector -# if inter_bone.length == 0 or perf_bone.length == 0: -# scaling = 1 -# else: -# scaling = perf_bone.length / inter_bone.length -# offset/=scaling -# empty.location = inter_bone.head + offset -# empty.keyframe_insert("location") - + def locOfOriginal(inter_bone, perf_bone): + if not perf_bone.name + "Org" in bpy.data.objects: + bpy.ops.object.add() + empty = bpy.context.active_object + empty.name = perf_bone.name + "Org" + empty.empty_draw_size = 0.01 + empty = bpy.data.objects[perf_bone.name + "Org"] + offset = perf_bone.vector + if inter_bone.length == 0 or perf_bone.length == 0: + scaling = 1 + else: + scaling = perf_bone.length / inter_bone.length + offset /= scaling + empty.location = inter_bone.head + offset + empty.keyframe_insert("location") + #Simple 1to1 retarget of a bone - def singleBoneRetarget(inter_bone,perf_bone): - perf_world_rotation = perf_bone.matrix * performer_obj.matrix_world + def singleBoneRetarget(inter_bone, perf_bone): + perf_world_rotation = perf_bone.matrix * performer_obj.matrix_world inter_world_base_rotation = inter_bone.bone.matrix_local * inter_obj.matrix_world inter_world_base_inv = Matrix(inter_world_base_rotation) inter_world_base_inv.invert() return (inter_world_base_inv.to_3x3() * perf_world_rotation.to_3x3()).to_4x4() - - #uses 1to1 and interpolation/averaging to match many to 1 retarget - def manyPerfToSingleInterRetarget(inter_bone,performer_bones_s): - retarget_matrices = [singleBoneRetarget(inter_bone,perf_bone) for perf_bone in performer_bones_s] + + #uses 1to1 and interpolation/averaging to match many to 1 retarget + def manyPerfToSingleInterRetarget(inter_bone, performer_bones_s): + retarget_matrices = [singleBoneRetarget(inter_bone, perf_bone) for perf_bone in performer_bones_s] lerp_matrix = Matrix() - for i in range(len(retarget_matrices)-1): + for i in range(len(retarget_matrices) - 1): first_mat = retarget_matrices[i] - next_mat = retarget_matrices[i+1] - lerp_matrix = first_mat.lerp(next_mat,0.5) + next_mat = retarget_matrices[i + 1] + lerp_matrix = first_mat.lerp(next_mat, 0.5) return lerp_matrix - - #determines the type of hierachy change needed and calls the - #right function + + #determines the type of hierachy change needed and calls the + #right function def retargetPerfToInter(inter_bone): - if inter_bone.name in bonemapr.keys(): + if inter_bone.name in bonemapr: perf_bone_name = bonemapr[inter_bone.name] #is it a 1 to many? - if type(bonemap[perf_bone_name[0]])==type((0,0)): + if isinstance(bonemap[perf_bone_name[0]], tuple): perf_bone = performer_bones[perf_bone_name[0]] if inter_bone.name == bonemap[perf_bone_name[0]][0]: - locOfOriginal(inter_bone,perf_bone) + locOfOriginal(inter_bone, perf_bone) else: # then its either a many to 1 or 1 to 1 - + if len(perf_bone_name) > 1: performer_bones_s = [performer_bones[name] for name in perf_bone_name] #we need to map several performance bone to a single for perf_bone in performer_bones_s: - locOfOriginal(inter_bone,perf_bone) - inter_bone.matrix_basis = manyPerfToSingleInterRetarget(inter_bone,performer_bones_s) + locOfOriginal(inter_bone, perf_bone) + inter_bone.matrix_basis = manyPerfToSingleInterRetarget(inter_bone, performer_bones_s) else: perf_bone = performer_bones[perf_bone_name[0]] - locOfOriginal(inter_bone,perf_bone) - inter_bone.matrix_basis = singleBoneRetarget(inter_bone,perf_bone) - + locOfOriginal(inter_bone, perf_bone) + inter_bone.matrix_basis = singleBoneRetarget(inter_bone, perf_bone) + inter_bone.keyframe_insert("rotation_quaternion") for child in inter_bone.children: retargetPerfToInter(child) - - #creates the intermediate armature object - bpy.ops.object.select_name(name=endu_name,extend=False) - bpy.ops.object.duplicate(linked=False) - bpy.context.active_object.name = "intermediate" - inter_obj = bpy.context.active_object + + #creates the intermediate armature object + inter_obj = enduser_obj.copy() + inter_obj.data = inter_obj.data.copy() # duplicate data + bpy.context.scene.objects.link(inter_obj) + inter_obj.name = "intermediate" + bpy.context.scene.objects.active = inter_obj bpy.ops.object.mode_set(mode='EDIT') - #resets roll + #resets roll bpy.ops.armature.calculate_roll(type='Z') bpy.ops.object.mode_set(mode="OBJECT") - inter_arm = bpy.data.armatures[endu_name+".001"] - inter_arm.name = "inter_arm" + inter_obj.data.name = "inter_arm" + inter_arm = inter_obj.data performer_bones = performer_obj.pose.bones - inter_bones = inter_obj.pose.bones - + inter_bones = inter_obj.pose.bones #clears inheritance for inter_bone in inter_bones: inter_bone.bone.use_inherit_rotation = False - - for t in range(s_frame,e_frame): + + for t in range(s_frame, e_frame): scene.frame_set(t) inter_bone = inter_bones[root] retargetPerfToInter(inter_bone) - - return inter_obj,inter_arm + + return inter_obj, inter_arm # this procedure copies the rotations over from the intermediate # armature to the end user one. -# As the hierarchies are 1 to 1, this is a simple matter of +# As the hierarchies are 1 to 1, this is a simple matter of # copying the rotation, while keeping in mind bone roll, parenting, etc. # TODO: Control Bones: If a certain bone is constrained in a way # that its rotation is determined by another (a control bone) # We should determine the right pos of the control bone. -# Scale: ? Should work but needs testing. -def retargetEnduser(inter_obj, enduser_obj,root,s_frame,e_frame,scene): - inter_bones = inter_obj.pose.bones +# Scale: ? Should work but needs testing. + + +def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene): + inter_bones = inter_obj.pose.bones end_bones = enduser_obj.pose.bones - + def bakeTransform(end_bone): src_bone = inter_bones[end_bone.name] trg_bone = end_bone bake_matrix = src_bone.matrix rest_matrix = trg_bone.bone.matrix_local - + if trg_bone.parent and trg_bone.bone.use_inherit_rotation: parent_mat = src_bone.parent.matrix parent_rest = trg_bone.parent.bone.matrix_local @@ -164,17 +186,17 @@ def retargetEnduser(inter_obj, enduser_obj,root,s_frame,e_frame,scene): parent_mat_inv.invert() bake_matrix = parent_mat_inv * bake_matrix rest_matrix = parent_rest_inv * rest_matrix - + rest_matrix_inv = rest_matrix.copy() rest_matrix_inv.invert() bake_matrix = rest_matrix_inv * bake_matrix trg_bone.matrix_basis = bake_matrix end_bone.keyframe_insert("rotation_quaternion") - + for bone in end_bone.children: bakeTransform(bone) - - for t in range(s_frame,e_frame): + + for t in range(s_frame, e_frame): scene.frame_set(t) end_bone = end_bones[root] bakeTransform(end_bone) @@ -182,98 +204,104 @@ def retargetEnduser(inter_obj, enduser_obj,root,s_frame,e_frame,scene): #recieves the performer feet bones as a variable # by "feet" I mean those bones that have plants # (they don't move, despite root moving) somewhere in the animation. -def copyTranslation(performer_obj,enduser_obj,perfFeet,bonemap,bonemapr,root,s_frame,e_frame,scene): + + +def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, root, s_frame, e_frame, scene): endFeet = [bonemap[perfBone] for perfBone in perfFeet] perfRoot = bonemapr[root][0] - locDictKeys = perfFeet+endFeet+[perfRoot] + locDictKeys = perfFeet + endFeet + [perfRoot] perf_bones = performer_obj.pose.bones end_bones = enduser_obj.pose.bones - + def tailLoc(bone): - return bone.center+(bone.vector/2) - + return bone.center + (bone.vector / 2) + #Step 1 - we create a dict that contains these keys: #(Performer) Hips, Feet #(End user) Feet # where the values are their world position on each (1,120) frame - + locDict = {} for key in locDictKeys: - locDict[key] = [] - - for t in range(scene.frame_start,scene.frame_end): + locDict[key] = [] + + for t in range(scene.frame_start, scene.frame_end): scene.frame_set(t) for bone in perfFeet: locDict[bone].append(tailLoc(perf_bones[bone])) locDict[perfRoot].append(tailLoc(perf_bones[perfRoot])) for bone in endFeet: locDict[bone].append(tailLoc(end_bones[bone])) - + # now we take our locDict and analyze it. - # we need to derive all chains - + # we need to derive all chains + locDeriv = {} for key in locDictKeys: locDeriv[key] = [] - + for key in locDict.keys(): graph = locDict[key] - for t in range(len(graph)-1): + for t in range(len(graph) - 1): x = graph[t] - xh = graph[t+1] - locDeriv[key].append(xh-x) - + xh = graph[t + 1] + locDeriv[key].append(xh - x) + # now find the plant frames, where perfFeet don't move much - + linearAvg = [] - + for key in perfFeet: - for i in range(len(locDeriv[key])-1): + for i in range(len(locDeriv[key]) - 1): v = locDeriv[key][i] hipV = locDeriv[perfRoot][i] endV = locDeriv[bonemap[key]][i] - if (v.length<0.1): + if (v.length < 0.1): #this is a plant frame. #lets see what the original hip delta is, and the corresponding #end bone's delta - if endV.length!=0: - linearAvg.append(hipV.length/endV.length) + if endV.length != 0: + linearAvg.append(hipV.length / endV.length) if linearAvg: - avg = sum(linearAvg)/len(linearAvg) - print("retargeted root motion should be "+ str(1/avg)+ " of original") - + avg = sum(linearAvg) / len(linearAvg) + print("retargeted root motion should be " + str(1 / avg) + " of original") + bpy.ops.object.add() stride_bone = bpy.context.active_object stride_bone.name = "stride_bone" - bpy.ops.object.select_name(name=stride_bone.name,extend=False) - bpy.ops.object.select_name(name=enduser_obj.name,extend=True) + bpy.ops.object.select_name(name=stride_bone.name, extend=False) + bpy.ops.object.select_name(name=enduser_obj.name, extend=True) bpy.ops.object.mode_set(mode='POSE') bpy.ops.pose.select_all(action='DESELECT') root_bone = end_bones[root] root_bone.bone.select = True bpy.ops.pose.constraint_add_with_targets(type='CHILD_OF') - for t in range(s_frame,e_frame): - scene.frame_set(t) - newTranslation = (tailLoc(perf_bones[perfRoot])/avg) + for t in range(s_frame, e_frame): + scene.frame_set(t) + newTranslation = (tailLoc(perf_bones[perfRoot]) / avg) stride_bone.location = newTranslation stride_bone.keyframe_insert("location") - def totalRetarget(): - perf_name = bpy.context.scene.performer - endu_name = bpy.context.scene.enduser - performer_obj = bpy.data.objects[perf_name] - enduser_obj = bpy.data.objects[endu_name] - end_arm = bpy.data.armatures[endu_name] - perf_arm = bpy.data.armatures[perf_name] + enduser_obj = bpy.context.active_object + performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj] + if enduser_obj is None or len(performer_obj) != 1: + print("Need active and selected armatures") + else: + performer_obj = performer_obj[0] + perf_arm = performer_obj.data + end_arm = enduser_obj.data scene = bpy.context.scene s_frame = scene.frame_start e_frame = scene.frame_end - bonemap, bonemapr, root = createDictionary(perf_arm) - inter_obj, inter_arm = createIntermediate(performer_obj,endu_name,bonemap, bonemapr,root,s_frame,e_frame,scene) - retargetEnduser(inter_obj, enduser_obj,root,s_frame,e_frame,scene) - copyTranslation(performer_obj,enduser_obj,["RightFoot","LeftFoot"],bonemap,bonemapr,root,s_frame,e_frame,scene) + bonemap, bonemapr, root = createDictionary(perf_arm) + inter_obj, inter_arm = createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_frame, e_frame, scene) + retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene) + copyTranslation(performer_obj, enduser_obj, ["RightFoot", "LeftFoot"], bonemap, bonemapr, root, s_frame, e_frame, scene) bpy.ops.object.mode_set(mode='OBJECT') - bpy.ops.object.select_name(name=inter_obj.name,extend=False) + bpy.ops.object.select_name(name=inter_obj.name, extend=False) bpy.ops.object.delete() + +if __name__ == "__main__": + totalRetarget() diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 5f59c368393..8454a99d4d5 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -1,3 +1,23 @@ +# ##### 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 ##### + +# + import bpy import time @@ -6,19 +26,18 @@ from bpy import * from mathutils import Vector from math import isfinite -bpy.types.Scene.performer = bpy.props.StringProperty() -bpy.types.Scene.enduser = bpy.props.StringProperty() bpy.types.Bone.map = bpy.props.StringProperty() import retarget import mocap_tools + class MocapPanel(bpy.types.Panel): bl_label = "Mocap tools" bl_space_type = "PROPERTIES" bl_region_type = "WINDOW" bl_context = "object" - + def draw(self, context): self.layout.label("Preprocessing") row = self.layout.row(align=True) @@ -32,66 +51,75 @@ class MocapPanel(bpy.types.Panel): row3 = self.layout.row(align=True) column1 = row3.column(align=True) column1.label("Performer Rig") - column1.prop_search(context.scene, "performer", context.scene, "objects") column2 = row3.column(align=True) column2.label("Enduser Rig") - column2.prop_search(context.scene, "enduser", context.scene, "objects") self.layout.label("Hierarchy mapping") - if context.scene.performer in bpy.data.armatures and context.scene.enduser in bpy.data.armatures: - perf = bpy.data.armatures[context.scene.performer] - enduser_arm = bpy.data.armatures[context.scene.enduser] - for bone in perf.bones: - row = self.layout.row(align=True) - row.label(bone.name) - row.prop_search(bone, "map", enduser_arm, "bones") - self.layout.operator("mocap.retarget", text='RETARGET!') - - - - + enduser_obj = bpy.context.active_object + performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj] + if enduser_obj is None or len(performer_obj) != 1: + self.layout.label("Select performer rig and target rig (as active)") + else: + performer_obj = performer_obj[0] + if performer_obj.data.name in bpy.data.armatures and enduser_obj.data.name in bpy.data.armatures: + perf = performer_obj.data + enduser_arm = enduser_obj.data + for bone in perf.bones: + row = self.layout.row(align=True) + row.label(bone.name) + row.prop_search(bone, "map", enduser_arm, "bones") + self.layout.operator("mocap.retarget", text='RETARGET!') + + class OBJECT_OT_RetargetButton(bpy.types.Operator): bl_idname = "mocap.retarget" bl_label = "Retargets active action from Performer to Enduser" - + def execute(self, context): retarget.totalRetarget() return {"FINISHED"} - + + class OBJECT_OT_ConvertSamplesButton(bpy.types.Operator): bl_idname = "mocap.samples" bl_label = "Converts samples / simplifies keyframes to beziers" - + def execute(self, context): mocap_tools.fcurves_simplify() return {"FINISHED"} - + + class OBJECT_OT_LooperButton(bpy.types.Operator): bl_idname = "mocap.looper" bl_label = "loops animation / sampled mocap data" - + def execute(self, context): mocap_tools.autoloop_anim() return {"FINISHED"} - + + class OBJECT_OT_DenoiseButton(bpy.types.Operator): bl_idname = "mocap.denoise" bl_label = "Denoises sampled mocap data " - + def execute(self, context): return {"FINISHED"} + class OBJECT_OT_LimitDOFButton(bpy.types.Operator): bl_idname = "mocap.limitdof" bl_label = "Analyzes animations Max/Min DOF and adds hard/soft constraints" - + def execute(self, context): return {"FINISHED"} + def register(): - bpy.utils.register_module(__name__) - + bpy.utils.register_module(__name__) + + def unregister(): bpy.utils.unregister_module(__name__) - -if __name__=="__main__": - register() + + +if __name__ == "__main__": + register() -- cgit v1.2.3 From 17da597cc83eaaacdb7d70bb8c8f74aee872f4d3 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Sun, 26 Jun 2011 19:54:29 +0000 Subject: Added IK functionality to retargeting. If rig contains an IK constraint, in addition to FK retarget it will place and keyframe the IK targets correctly --- release/scripts/modules/retarget.py | 59 ++++++++++++++++++++++++++++++++----- release/scripts/startup/ui_mocap.py | 26 +++++++++++----- 2 files changed, 70 insertions(+), 15 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 8fe8c6937bb..8cbd7129dd3 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -269,13 +269,6 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, roo bpy.ops.object.add() stride_bone = bpy.context.active_object stride_bone.name = "stride_bone" - bpy.ops.object.select_name(name=stride_bone.name, extend=False) - bpy.ops.object.select_name(name=enduser_obj.name, extend=True) - bpy.ops.object.mode_set(mode='POSE') - bpy.ops.pose.select_all(action='DESELECT') - root_bone = end_bones[root] - root_bone.bone.select = True - bpy.ops.pose.constraint_add_with_targets(type='CHILD_OF') for t in range(s_frame, e_frame): scene.frame_set(t) newTranslation = (tailLoc(perf_bones[perfRoot]) / avg) @@ -283,7 +276,57 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, roo stride_bone.keyframe_insert("location") +def IKRetarget(bonemap, bonemapr, performer_obj, enduser_obj, s_frame, e_frame, scene): + end_bones = enduser_obj.pose.bones + for pose_bone in end_bones: + if "IK" in [constraint.type for constraint in pose_bone.constraints]: + # set constraint target to corresponding empty if targetless, + # if not, keyframe current target to corresponding empty + perf_bone = bonemapr[pose_bone.name] + if isinstance(perf_bone, list): + perf_bone = bonemapr[pose_bone.name][-1] + end_empty = bpy.data.objects[perf_bone + "Org"] + ik_constraint = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"][0] + if not ik_constraint.target: + ik_constraint.target = end_empty + else: + #Bone target + target_is_bone = False + if ik_constraint.subtarget: + target = ik_constraint.target.pose.bones[ik_constraint.subtarget] + target.bone.use_local_location = False + target_is_bone = True + else: + target = ik_constraint.target + for t in range(s_frame, e_frame): + scene.frame_set(t) + if target_is_bone: + final_loc = end_empty.location - target.bone.matrix_local.to_translation() + else: + final_loc = end_empty.location + target.location = final_loc + target.keyframe_insert("location") + ik_constraint.mute = False + + +def turnOffIK(enduser_obj): + end_bones = enduser_obj.pose.bones + for pose_bone in end_bones: + if pose_bone.is_in_ik_chain: + pass + # TODO: + # set stiffness according to place on chain + # and values from analysis that is stored in the bone + #pose_bone.ik_stiffness_x = 0.5 + #pose_bone.ik_stiffness_y = 0.5 + #pose_bone.ik_stiffness_z = 0.5 + if "IK" in [constraint.type for constraint in pose_bone.constraints]: + ik_constraint = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"][0] + ik_constraint.mute = True + + def totalRetarget(): + print("retargeting...") enduser_obj = bpy.context.active_object performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj] if enduser_obj is None or len(performer_obj) != 1: @@ -296,9 +339,11 @@ def totalRetarget(): s_frame = scene.frame_start e_frame = scene.frame_end bonemap, bonemapr, root = createDictionary(perf_arm) + turnOffIK(enduser_obj) inter_obj, inter_arm = createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_frame, e_frame, scene) retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene) copyTranslation(performer_obj, enduser_obj, ["RightFoot", "LeftFoot"], bonemap, bonemapr, root, s_frame, e_frame, scene) + IKRetarget(bonemap, bonemapr, performer_obj, enduser_obj, s_frame, e_frame, scene) bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_name(name=inter_obj.name, extend=False) bpy.ops.object.delete() diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 8454a99d4d5..9c540771b44 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -60,14 +60,24 @@ class MocapPanel(bpy.types.Panel): self.layout.label("Select performer rig and target rig (as active)") else: performer_obj = performer_obj[0] - if performer_obj.data.name in bpy.data.armatures and enduser_obj.data.name in bpy.data.armatures: - perf = performer_obj.data - enduser_arm = enduser_obj.data - for bone in perf.bones: - row = self.layout.row(align=True) - row.label(bone.name) - row.prop_search(bone, "map", enduser_arm, "bones") - self.layout.operator("mocap.retarget", text='RETARGET!') + if performer_obj.data and enduser_obj.data: + if performer_obj.data.name in bpy.data.armatures and enduser_obj.data.name in bpy.data.armatures: + perf = performer_obj.data + enduser_arm = enduser_obj.data + perf_pose_bones = enduser_obj.pose.bones + for bone in perf.bones: + row = self.layout.row(align=True) + row.label(bone.name) + row.prop_search(bone, "map", enduser_arm, "bones") + label_mod = "FK" + if bone.map: + pose_bone = perf_pose_bones[bone.map] + if pose_bone.is_in_ik_chain: + label_mod = "IK" + if "IK" in [constraint.type for constraint in pose_bone.constraints]: + label_mod = "IKEnd" + row.label(label_mod) + self.layout.operator("mocap.retarget", text='RETARGET!') class OBJECT_OT_RetargetButton(bpy.types.Operator): -- cgit v1.2.3 From 46a4f47a5de438a5a76223cf1659e09aaf21a3d3 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Mon, 27 Jun 2011 12:46:53 +0000 Subject: Added more IK functionality to UI. You can now toggle IK for selected bones. --- release/scripts/startup/ui_mocap.py | 58 +++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 5 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 9c540771b44..014daa7ef8a 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -26,8 +26,54 @@ from bpy import * from mathutils import Vector from math import isfinite +def toggleIKBone(self, context): + if self.IKRetarget: + if not self.is_in_ik_chain: + print(self.name + " IK toggled ON!") + ik = self.constraints.new('IK') + #ik the whole chain up to the root + chainLen = len(self.bone.parent_recursive) + ik.chain_count = chainLen + for bone in self.parent_recursive: + if bone.is_in_ik_chain: + bone.IKRetarget = True + else: + print(self.name + " IK toggled OFF!") + cnstrn_bone = False + if hasIKConstraint(self): + cnstrn_bone = self + elif self.is_in_ik_chain: + cnstrn_bone = [child for child in self.children_recursive if hasIKConstraint(child)][0] + if cnstrn_bone: + # remove constraint, and update IK retarget for all parents of cnstrn_bone up to chain_len + ik = [constraint for constraint in cnstrn_bone.constraints if constraint.type == "IK"][0] + cnstrn_bone.constraints.remove(ik) + cnstrn_bone.IKRetarget = False + for bone in cnstrn_bone.parent_recursive: + if not bone.is_in_ik_chain: + bone.IKRetarget = False + bpy.types.Bone.map = bpy.props.StringProperty() +bpy.types.PoseBone.IKRetarget = bpy.props.BoolProperty(name="IK", + description = "Toggles IK Retargeting method for given bone", + update = toggleIKBone) + +def hasIKConstraint(pose_bone): + return ("IK" in [constraint.type for constraint in pose_bone.constraints]) + +def updateIKRetarget(): + for obj in bpy.data.objects: + if obj.pose: + bones = obj.pose.bones + for pose_bone in bones: + if pose_bone.is_in_ik_chain or hasIKConstraint(pose_bone): + pose_bone.IKRetarget = True + else: + pose_bone.IKRetarget = False + +updateIKRetarget() + import retarget import mocap_tools @@ -66,17 +112,19 @@ class MocapPanel(bpy.types.Panel): enduser_arm = enduser_obj.data perf_pose_bones = enduser_obj.pose.bones for bone in perf.bones: - row = self.layout.row(align=True) + row = self.layout.row() row.label(bone.name) row.prop_search(bone, "map", enduser_arm, "bones") label_mod = "FK" if bone.map: pose_bone = perf_pose_bones[bone.map] if pose_bone.is_in_ik_chain: - label_mod = "IK" - if "IK" in [constraint.type for constraint in pose_bone.constraints]: - label_mod = "IKEnd" + label_mod = "ik chain" + if hasIKConstraint(pose_bone): + label_mod = "ik end" + row.prop(pose_bone, 'IKRetarget') row.label(label_mod) + self.layout.operator("mocap.retarget", text='RETARGET!') @@ -132,4 +180,4 @@ def unregister(): if __name__ == "__main__": - register() + register() \ No newline at end of file -- cgit v1.2.3 From ff5dbbe1b875d8354cd9d45f6873efcebd78b008 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Mon, 27 Jun 2011 12:48:30 +0000 Subject: Some bugfixing and tweaking for retargeting. Script works now regardless of world transform on performer and end user rigs. This breaks stride bone functionality, will be addressed in next commit --- release/scripts/modules/retarget.py | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 8cbd7129dd3..7688f9657a2 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -75,7 +75,8 @@ def createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_fr bpy.ops.object.add() empty = bpy.context.active_object empty.name = perf_bone.name + "Org" - empty.empty_draw_size = 0.01 + empty.empty_draw_size = 0.1 + #empty.parent = enduser_obj empty = bpy.data.objects[perf_bone.name + "Org"] offset = perf_bone.vector if inter_bone.length == 0 or perf_bone.length == 0: @@ -262,18 +263,19 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, roo #end bone's delta if endV.length != 0: linearAvg.append(hipV.length / endV.length) + + bpy.ops.object.add() + stride_bone = bpy.context.active_object + stride_bone.name = "stride_bone" + if linearAvg: avg = sum(linearAvg) / len(linearAvg) - print("retargeted root motion should be " + str(1 / avg) + " of original") - - bpy.ops.object.add() - stride_bone = bpy.context.active_object - stride_bone.name = "stride_bone" for t in range(s_frame, e_frame): scene.frame_set(t) newTranslation = (tailLoc(perf_bones[perfRoot]) / avg) stride_bone.location = newTranslation stride_bone.keyframe_insert("location") + return stride_bone def IKRetarget(bonemap, bonemapr, performer_obj, enduser_obj, s_frame, e_frame, scene): @@ -324,6 +326,22 @@ def turnOffIK(enduser_obj): ik_constraint = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"][0] ik_constraint.mute = True +def cleanAndStoreObjMat(performer_obj,enduser_obj): + perf_obj_mat = performer_obj.matrix_world.copy() + enduser_obj_mat = enduser_obj.matrix_world.copy() + zero_mat = Matrix()#Matrix(((0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0))) + performer_obj.matrix_world = zero_mat + enduser_obj.matrix_world = zero_mat + return perf_obj_mat, enduser_obj_mat + +def restoreObjMat(performer_obj,enduser_obj,perf_obj_mat,enduser_obj_mat): + perf_bones = performer_obj.pose.bones + for perf_bone in perf_bones: + if perf_bone.name + "Org" in bpy.data.objects: + empty = bpy.data.objects[perf_bone.name + "Org"] + empty.parent = enduser_obj + performer_obj.matrix_world = perf_obj_mat + enduser_obj.matrix_world = enduser_obj_mat def totalRetarget(): print("retargeting...") @@ -339,14 +357,16 @@ def totalRetarget(): s_frame = scene.frame_start e_frame = scene.frame_end bonemap, bonemapr, root = createDictionary(perf_arm) + perf_obj_mat, enduser_obj_mat = cleanAndStoreObjMat(performer_obj,enduser_obj) turnOffIK(enduser_obj) inter_obj, inter_arm = createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_frame, e_frame, scene) retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene) - copyTranslation(performer_obj, enduser_obj, ["RightFoot", "LeftFoot"], bonemap, bonemapr, root, s_frame, e_frame, scene) + stride_bone = copyTranslation(performer_obj, enduser_obj, ["RightFoot", "LeftFoot"], bonemap, bonemapr, root, s_frame, e_frame, scene) IKRetarget(bonemap, bonemapr, performer_obj, enduser_obj, s_frame, e_frame, scene) + restoreObjMat(performer_obj,enduser_obj,perf_obj_mat,enduser_obj_mat) bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_name(name=inter_obj.name, extend=False) bpy.ops.object.delete() if __name__ == "__main__": - totalRetarget() + totalRetarget() \ No newline at end of file -- cgit v1.2.3 From 2710c567b9deaba51f7d3bc2572a14872cb12641 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 29 Jun 2011 13:00:19 +0000 Subject: Animation Editors - Small Visual Tweaks for Usability == Datablock filters in the headers are now hidden by default == This has been done because users were generally not frequently toggling these, so quick access vs screen-estate cost wasn't really worth it to have these always showing and taking up space on the header. Usage notes: - To show these again, click on the "Filter more..." toggle. - The "Filter more..." button DOES NOT affect whether those filters apply. Design notes: - I tried many other button/icon combinations, but those were either too space-hogging, vague, or had wrong button order. - I also tried putting a box around these, but there was too much padding. - The ordering of the filters has also been modified a bit so that the group/fcurve-name filters occur earlier in the list, given that they're used more frequently == Graph Editor - Use Fancy Drawing == Renamed this option to "Use High Quality Drawing" as suggested by Matt. "Fancy" isn't really descriptive enough. == Icons for Mode Dropdowns == The mode dropdowns in the DopeSheet and Graph Editors now have icons. - These were important enough (compared to the auto-snap mode) that some visual decoration was perhaps warranted. - It makes it easier to see at a glance what mode the view is in Icon choices: - In some cases, the icons seem like quite a natural fit IMO (i.e. outliner<->dopesheet, key<->shapekey editor, grease pencil, fcurve editor) - Action Editor uses an "object" icon to indicate that this is object- level only for now (though I hope to find a way to address this soon/later). This will be kept like this until then. - There isn't any icon for drivers, so after trying a few alternatives, I settled on area-link icon, since it ties together two entities using some link. --- release/scripts/startup/bl_ui/space_dopesheet.py | 39 ++++++++++++++---------- release/scripts/startup/bl_ui/space_graph.py | 2 +- 2 files changed, 24 insertions(+), 17 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 930a2029d32..ee830da6860 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -33,14 +33,33 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False): row.prop(dopesheet, "show_only_selected", text="") row.prop(dopesheet, "show_hidden", text="") + if is_nla: + row.prop(dopesheet, "show_missing_nla", text="") + if not genericFiltersOnly: + if bpy.data.groups: + row = layout.row(align=True) + row.prop(dopesheet, "show_only_group_objects", text="") + if dopesheet.show_only_group_objects: + row.prop(dopesheet, "filter_group", text="") + + if not is_nla: row = layout.row(align=True) - row.prop(dopesheet, "show_transforms", text="") + row.prop(dopesheet, "show_only_matching_fcurves", text="") + if dopesheet.show_only_matching_fcurves: + row.prop(dopesheet, "filter_fcurve_name", text="") - if is_nla: - row.prop(dopesheet, "show_missing_nla", text="") + row = layout.row() + row.prop(dopesheet, "show_datablock_filters", text="more...", icon='FILTER') - row = layout.row(align=True) + if (not genericFiltersOnly) and (dopesheet.show_datablock_filters): + # TODO: put a box around these? + subrow = row.row() + + row = subrow.row(align=True) + row.prop(dopesheet, "show_transforms", text="") + + row = subrow.row(align=True) row.prop(dopesheet, "show_scenes", text="") row.prop(dopesheet, "show_worlds", text="") row.prop(dopesheet, "show_nodes", text="") @@ -68,18 +87,6 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False): if bpy.data.particles: row.prop(dopesheet, "show_particles", text="") - if bpy.data.groups: - row = layout.row(align=True) - row.prop(dopesheet, "show_only_group_objects", text="") - if dopesheet.show_only_group_objects: - row.prop(dopesheet, "filter_group", text="") - - if not is_nla: - row = layout.row(align=True) - row.prop(dopesheet, "show_only_matching_fcurves", text="") - if dopesheet.show_only_matching_fcurves: - row.prop(dopesheet, "filter_fcurve_name", text="") - ####################################### # DopeSheet Editor - General/Standard UI diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index bfc1a0e3a23..1987143f660 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -81,7 +81,7 @@ class GRAPH_MT_view(bpy.types.Menu): layout.prop(st, "use_auto_merge_keyframes") layout.separator() - layout.prop(st, "use_fancy_drawing") + layout.prop(st, "use_beauty_drawing") layout.separator() if st.show_handles: -- cgit v1.2.3 From 333e8257989610410d6ea7cea353e06ba638e4a7 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Wed, 29 Jun 2011 14:29:52 +0000 Subject: Created UI and Group Property for Motion Capture constraints, to be used to fix up animation after retargeting --- release/scripts/startup/ui_mocap.py | 148 ++++++++++++++++++++++++++++++++++-- 1 file changed, 141 insertions(+), 7 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 014daa7ef8a..4abc777f59e 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -26,12 +26,70 @@ from bpy import * from mathutils import Vector from math import isfinite +# MocapConstraint class +# Defines MocapConstraint datatype, used to add and configute mocap constraints +# Attached to Armature data + + +class MocapConstraint(bpy.types.PropertyGroup): + name = bpy.props.StringProperty(name = "Name", + default = "Mocap Constraint", + description = "Name of Mocap Constraint") + boneA = bpy.props.StringProperty(name = "Bone", + default = "", + description = "Constrained Bone") + boneB = bpy.props.StringProperty(name = "Bone (2)", + default = "", + description = "Other Constrained Bone (optional, depends on type)") + s_frame = bpy.props.IntProperty(name = "S", + default = 1, + description = "Start frame of constraint") + e_frame = bpy.props.IntProperty(name = "E", + default = 500, + description = "End frame of constrain") + targetMesh = bpy.props.StringProperty(name = "Mesh", + default = "", + description = "Target of Constraint - Mesh (optional, depends on type)") + active = bpy.props.BoolProperty(name = "Active", + default = True, + description = "Constraint is active") + baked = bpy.props.BoolProperty(name = "Baked / Applied", + default = False, + description = "Constraint has been baked to NLA layer") + targetFrame = bpy.props.IntProperty(name = "Frame", + default = 1, + description = "Target of Constraint - Frame (optional, depends on type)") + targetPoint = bpy.props.FloatVectorProperty(name = "Point", size = 3, + subtype = "XYZ", default = (0.0, 0.0, 0.0), + description = "Target of Constraint - Point") + targetSpace = bpy.props.EnumProperty( + items = [("world", "World Space", "Evaluate target in global space"), + ("object", "Object space", "Evaluate target in object space"), + ("boneb", "Other Bone Space", "Evaluate target in specified other bone space")], + name = "Space", + description = "In which space should Point type target be evaluated") + type = bpy.props.EnumProperty(name="Type of constraint", + items = [("point", "Maintain Position", "Bone is at a specific point"), + ("freeze", "Maintain Position at frame", "Bone does not move from location specified in target frame"), + ("floor", "Stay above", "Bone does not cross specified mesh object eg floor"), + ("distance", "Maintain distance", "Target bones maintained specified distance")], + description = "Type of constraint") + realConstraint = bpy.props.StringProperty() + + +bpy.utils.register_class(MocapConstraint) + +bpy.types.Armature.mocap_constraints = bpy.props.CollectionProperty(type=MocapConstraint) + +#Update function for IK functionality. Is called when IK prop checkboxes are toggled. + + def toggleIKBone(self, context): if self.IKRetarget: if not self.is_in_ik_chain: print(self.name + " IK toggled ON!") ik = self.constraints.new('IK') - #ik the whole chain up to the root + #ik the whole chain up to the root, excluding chainLen = len(self.bone.parent_recursive) ik.chain_count = chainLen for bone in self.parent_recursive: @@ -52,17 +110,23 @@ def toggleIKBone(self, context): for bone in cnstrn_bone.parent_recursive: if not bone.is_in_ik_chain: bone.IKRetarget = False - bpy.types.Bone.map = bpy.props.StringProperty() -bpy.types.PoseBone.IKRetarget = bpy.props.BoolProperty(name="IK", +bpy.types.PoseBone.IKRetarget = bpy.props.BoolProperty(name = "IK", description = "Toggles IK Retargeting method for given bone", - update = toggleIKBone) + update = toggleIKBone, default = False) + def hasIKConstraint(pose_bone): + #utility function / predicate, returns True if given bone has IK constraint return ("IK" in [constraint.type for constraint in pose_bone.constraints]) - + + def updateIKRetarget(): + # ensures that Blender constraints and IK properties are in sync + # currently runs when module is loaded, should run when scene is loaded + # or user adds a constraint to armature. Will be corrected in the future, + # once python callbacks are implemented for obj in bpy.data.objects: if obj.pose: bones = obj.pose.bones @@ -79,6 +143,7 @@ import mocap_tools class MocapPanel(bpy.types.Panel): + # Motion capture retargeting panel bl_label = "Mocap tools" bl_space_type = "PROPERTIES" bl_region_type = "WINDOW" @@ -124,10 +189,55 @@ class MocapPanel(bpy.types.Panel): label_mod = "ik end" row.prop(pose_bone, 'IKRetarget') row.label(label_mod) - + self.layout.operator("mocap.retarget", text='RETARGET!') +class MocapConstraintsPanel(bpy.types.Panel): + #Motion capture constraints panel + bl_label = "Mocap constraints" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "object" + + def draw(self, context): + layout = self.layout + if context.active_object: + if context.active_object.data: + if context.active_object.data.name in bpy.data.armatures: + enduser_obj = context.active_object + enduser_arm = enduser_obj.data + layout.operator("mocap.addconstraint", text = 'Add constraint') + layout.separator() + for i, m_constraint in enumerate(enduser_arm.mocap_constraints): + box = layout.box() + box.prop(m_constraint, 'name') + box.prop(m_constraint, 'type') + box.prop_search(m_constraint, 'boneA', enduser_obj.pose, "bones") + if m_constraint.type == "distance" or m_constraint.type == "point": + box.prop_search(m_constraint, 'boneB', enduser_obj.pose, "bones") + frameRow = box.row() + frameRow.label("Frame Range:") + frameRow.prop(m_constraint, 's_frame') + frameRow.prop(m_constraint, 'e_frame') + targetRow = box.row() + targetLabelCol = targetRow.column() + targetLabelCol.label("Target settings:") + targetPropCol = targetRow.column() + if m_constraint.type == "floor": + targetPropCol.prop_search(m_constraint, 'targetMesh', bpy.data, "objects") + if m_constraint.type == "freeze": + targetPropCol.prop(m_constraint, 'targetFrame') + if m_constraint.type == "point": + targetPropCol.prop(m_constraint, 'targetPoint') + box.prop(m_constraint, 'targetSpace') + checkRow = box.row() + checkRow.prop(m_constraint, 'active') + checkRow.prop(m_constraint, 'baked') + layout.operator("mocap.removeconstraint", text = "Remove constraint").constraint = i + layout.separator() + + class OBJECT_OT_RetargetButton(bpy.types.Operator): bl_idname = "mocap.retarget" bl_label = "Retargets active action from Performer to Enduser" @@ -171,6 +281,30 @@ class OBJECT_OT_LimitDOFButton(bpy.types.Operator): return {"FINISHED"} +class OBJECT_OT_AddMocapConstraint(bpy.types.Operator): + bl_idname = "mocap.addconstraint" + bl_label = "Add constraint to target armature" + + def execute(self, context): + enduser_obj = bpy.context.active_object + enduser_arm = enduser_obj.data + newCon = enduser_arm.mocap_constraints.add() + return {"FINISHED"} + + +class OBJECT_OT_RemoveMocapConstraint(bpy.types.Operator): + bl_idname = "mocap.removeconstraint" + bl_label = "Removes constraints from target armature" + constraint = bpy.props.IntProperty() + + def execute(self, context): + enduser_obj = bpy.context.active_object + enduser_arm = enduser_obj.data + constraints = enduser_arm.mocap_constraints + constraints.remove(self.constraint) + return {"FINISHED"} + + def register(): bpy.utils.register_module(__name__) @@ -180,4 +314,4 @@ def unregister(): if __name__ == "__main__": - register() \ No newline at end of file + register() -- cgit v1.2.3 From 8d4ea1b15544ed88d80bcbe687324c8321e83b07 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 30 Jun 2011 01:13:15 +0000 Subject: Tweak to the toggle to show/hide datablock filtering items in animedit headers --- release/scripts/startup/bl_ui/space_dopesheet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index ee830da6860..525e87db284 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -50,7 +50,7 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False): row.prop(dopesheet, "filter_fcurve_name", text="") row = layout.row() - row.prop(dopesheet, "show_datablock_filters", text="more...", icon='FILTER') + row.prop(dopesheet, "show_datablock_filters", text="Filters", icon='DISCLOSURE_TRI_RIGHT') if (not genericFiltersOnly) and (dopesheet.show_datablock_filters): # TODO: put a box around these? -- cgit v1.2.3 From 77dbc5c9141558ec2cfb08772857cf2048f9c58c Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 1 Jul 2011 02:37:44 +0000 Subject: Icons! Animation Editor toggle tweaks: * By popular request, curve visibility toggles in the Graph Editor are now represented using the eyeball icons * Muting is now represented by a speaker icon (a speaker for this purpose seems fairly common?) New icons: * Keying Sets now have their own icons (as found in a proposal on jendrzych's "Pixel Sized" blog) * Drivers also have their own icon now. This is just a hacky one I've devised which doesn't look that great. Suggestions on this are very welcome. --- release/datafiles/blenderbuttons | Bin 210335 -> 211658 bytes 1 file changed, 0 insertions(+), 0 deletions(-) (limited to 'release') diff --git a/release/datafiles/blenderbuttons b/release/datafiles/blenderbuttons index 9872e53585e..99b464095ed 100644 Binary files a/release/datafiles/blenderbuttons and b/release/datafiles/blenderbuttons differ -- cgit v1.2.3 From 8c3f2923fdc0626d4c2e7f6307c1ec4fd0e8c7f3 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Sat, 2 Jul 2011 18:24:05 +0000 Subject: Early commit of mocap constraint work. Still very much a WIP, but Point constraints should work - but buggy. --- release/scripts/modules/mocap_constraints.py | 141 +++++++++++++++++++++++++++ release/scripts/modules/retarget.py | 37 +++---- release/scripts/startup/ui_mocap.py | 117 ++++++++++++---------- 3 files changed, 227 insertions(+), 68 deletions(-) create mode 100644 release/scripts/modules/mocap_constraints.py (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py new file mode 100644 index 00000000000..1251786d882 --- /dev/null +++ b/release/scripts/modules/mocap_constraints.py @@ -0,0 +1,141 @@ +# ##### 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 ##### + +# + +import bpy +from mathutils import * + +### Utility Functions + + +def hasIKConstraint(pose_bone): + #utility function / predicate, returns True if given bone has IK constraint + return ("IK" in [constraint.type for constraint in pose_bone.constraints]) + + +def getConsObj(bone): + #utility function - returns related IK target if bone has IK + ik = [constraint for constraint in bone.constraints if constraint.type == "IK"] + if ik: + ik = ik[0] + cons_obj = ik.target + if ik.subtarget: + cons_obj = ik.target.pose.bones[ik.subtarget] + else: + cons_obj = bone + return cons_obj + +### And and Remove Constraints (called from operators) + + +def addNewConstraint(m_constraint, cons_obj): + if m_constraint.type == "point" or m_constraint.type == "freeze": + c_type = "LIMIT_LOCATION" + if m_constraint.type == "distance": + c_type = "LIMIT_DISTANCE" + if m_constraint.type == "floor": + c_type = "FLOOR" + real_constraint = cons_obj.constraints.new(c_type) + real_constraint.name = "Mocap constraint " + str(len(cons_obj.constraints)) + m_constraint.real_constraint_bone = cons_obj.name + m_constraint.real_constraint = real_constraint.name + setConstraint(m_constraint) + + +def removeConstraint(m_constraint, cons_obj): + oldConstraint = cons_obj.constraints[m_constraint.real_constraint] + cons_obj.constraints.remove(oldConstraint) + +### Update functions. There are 3: UpdateType, UpdateBone +### and update for the others. + + +def updateConstraint(self, context): + setConstraint(self) + + +def updateConstraintType(m_constraint, context): + pass + #If the constraint exists, we need to remove it + #Then create a new one. + + +def updateConstraintTargetBone(m_constraint, context): + #If the constraint exists, we need to remove it + #from the old bone + obj = context.active_object + bones = obj.pose.bones + if m_constraint.real_constraint: + bone = bones[m_constraint.real_constraint_bone] + cons_obj = getConsObj(bone) + removeConstraint(m_constraint, cons_obj) + #Regardless, after that we create a new constraint + bone = bones[m_constraint.constrained_bone] + cons_obj = getConsObj(bone) + addNewConstraint(m_constraint, cons_obj) + + +# Function that copies all settings from m_constraint to the real Blender constraints +# Is only called when blender constraint already exists +def setConstraint(m_constraint): + if not m_constraint.constrained_bone: + return + obj = bpy.context.active_object + bones = obj.pose.bones + bone = bones[m_constraint.constrained_bone] + cons_obj = getConsObj(bone) + real_constraint = cons_obj.constraints[m_constraint.real_constraint] + + #frame changing section + fcurves = obj.animation_data.action.fcurves + influence_RNA = real_constraint.path_from_id("influence") + fcurve = [fcurve for fcurve in fcurves if fcurve.data_path == influence_RNA] + #clear the fcurve and set the frames. + if fcurve: + fcurve = fcurve[0] + for i in range(len(fcurve.keyframe_points) - 1, 0, -1): + fcurve.keyframe_points.remove(fcurve.keyframe_points[i]) + s, e = bpy.context.scene.frame_start, bpy.context.scene.frame_end + real_constraint.influence = 0 + real_constraint.keyframe_insert(data_path="influence", frame=s) + real_constraint.keyframe_insert(data_path="influence", frame=e) + s, e = m_constraint.s_frame, m_constraint.e_frame + real_constraint.influence = 1 + real_constraint.keyframe_insert(data_path="influence", frame=s) + real_constraint.keyframe_insert(data_path="influence", frame=e) + real_constraint.influence = 0 + real_constraint.keyframe_insert(data_path="influence", frame=s - 10) + real_constraint.keyframe_insert(data_path="influence", frame=e + 10) + + #Set the blender constraint parameters + if m_constraint.type == "point": + real_constraint.target_space = "WORLD" # temporary for now, just World is supported + x, y, z = m_constraint.targetPoint + real_constraint.max_x = x + real_constraint.max_y = y + real_constraint.max_z = z + real_constraint.min_x = x + real_constraint.min_y = y + real_constraint.min_z = z + real_constraint.use_max_x = True + real_constraint.use_max_y = True + real_constraint.use_max_z = True + real_constraint.use_min_x = True + real_constraint.use_min_y = True + real_constraint.use_min_z = True diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 7688f9657a2..3ce90f64075 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -71,13 +71,13 @@ def createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_fr #useful for storing the important data in the original motion #i.e. using this empty to IK the chain to that pos / DEBUG def locOfOriginal(inter_bone, perf_bone): - if not perf_bone.name + "Org" in bpy.data.objects: + if not inter_bone.name + "Org" in bpy.data.objects: bpy.ops.object.add() empty = bpy.context.active_object - empty.name = perf_bone.name + "Org" + empty.name = inter_bone.name + "Org" empty.empty_draw_size = 0.1 #empty.parent = enduser_obj - empty = bpy.data.objects[perf_bone.name + "Org"] + empty = bpy.data.objects[inter_bone.name + "Org"] offset = perf_bone.vector if inter_bone.length == 0 or perf_bone.length == 0: scaling = 1 @@ -263,17 +263,17 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, roo #end bone's delta if endV.length != 0: linearAvg.append(hipV.length / endV.length) - + bpy.ops.object.add() stride_bone = bpy.context.active_object stride_bone.name = "stride_bone" - + if linearAvg: avg = sum(linearAvg) / len(linearAvg) for t in range(s_frame, e_frame): scene.frame_set(t) newTranslation = (tailLoc(perf_bones[perfRoot]) / avg) - stride_bone.location = newTranslation + stride_bone.location = newTranslation * enduser_obj.matrix_world stride_bone.keyframe_insert("location") return stride_bone @@ -287,7 +287,7 @@ def IKRetarget(bonemap, bonemapr, performer_obj, enduser_obj, s_frame, e_frame, perf_bone = bonemapr[pose_bone.name] if isinstance(perf_bone, list): perf_bone = bonemapr[pose_bone.name][-1] - end_empty = bpy.data.objects[perf_bone + "Org"] + end_empty = bpy.data.objects[pose_bone.name + "Org"] ik_constraint = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"][0] if not ik_constraint.target: ik_constraint.target = end_empty @@ -326,23 +326,26 @@ def turnOffIK(enduser_obj): ik_constraint = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"][0] ik_constraint.mute = True -def cleanAndStoreObjMat(performer_obj,enduser_obj): + +def cleanAndStoreObjMat(performer_obj, enduser_obj): perf_obj_mat = performer_obj.matrix_world.copy() enduser_obj_mat = enduser_obj.matrix_world.copy() - zero_mat = Matrix()#Matrix(((0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0))) + zero_mat = Matrix() # Matrix(((0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0))) performer_obj.matrix_world = zero_mat enduser_obj.matrix_world = zero_mat return perf_obj_mat, enduser_obj_mat -def restoreObjMat(performer_obj,enduser_obj,perf_obj_mat,enduser_obj_mat): - perf_bones = performer_obj.pose.bones - for perf_bone in perf_bones: - if perf_bone.name + "Org" in bpy.data.objects: - empty = bpy.data.objects[perf_bone.name + "Org"] + +def restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone): + pose_bones = enduser_obj.pose.bones + for pose_bone in pose_bones: + if pose_bone.name + "Org" in bpy.data.objects: + empty = bpy.data.objects[pose_bone.name + "Org"] empty.parent = enduser_obj performer_obj.matrix_world = perf_obj_mat enduser_obj.matrix_world = enduser_obj_mat + def totalRetarget(): print("retargeting...") enduser_obj = bpy.context.active_object @@ -357,16 +360,16 @@ def totalRetarget(): s_frame = scene.frame_start e_frame = scene.frame_end bonemap, bonemapr, root = createDictionary(perf_arm) - perf_obj_mat, enduser_obj_mat = cleanAndStoreObjMat(performer_obj,enduser_obj) + perf_obj_mat, enduser_obj_mat = cleanAndStoreObjMat(performer_obj, enduser_obj) turnOffIK(enduser_obj) inter_obj, inter_arm = createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_frame, e_frame, scene) retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene) stride_bone = copyTranslation(performer_obj, enduser_obj, ["RightFoot", "LeftFoot"], bonemap, bonemapr, root, s_frame, e_frame, scene) IKRetarget(bonemap, bonemapr, performer_obj, enduser_obj, s_frame, e_frame, scene) - restoreObjMat(performer_obj,enduser_obj,perf_obj_mat,enduser_obj_mat) + restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone) bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_name(name=inter_obj.name, extend=False) bpy.ops.object.delete() if __name__ == "__main__": - totalRetarget() \ No newline at end of file + totalRetarget() diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 4abc777f59e..4273eb74984 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -19,12 +19,10 @@ # import bpy -import time from bpy.props import * from bpy import * -from mathutils import Vector -from math import isfinite +from mocap_constraints import * # MocapConstraint class # Defines MocapConstraint datatype, used to add and configute mocap constraints @@ -32,49 +30,62 @@ from math import isfinite class MocapConstraint(bpy.types.PropertyGroup): - name = bpy.props.StringProperty(name = "Name", - default = "Mocap Constraint", - description = "Name of Mocap Constraint") - boneA = bpy.props.StringProperty(name = "Bone", - default = "", - description = "Constrained Bone") - boneB = bpy.props.StringProperty(name = "Bone (2)", - default = "", - description = "Other Constrained Bone (optional, depends on type)") - s_frame = bpy.props.IntProperty(name = "S", - default = 1, - description = "Start frame of constraint") - e_frame = bpy.props.IntProperty(name = "E", - default = 500, - description = "End frame of constrain") - targetMesh = bpy.props.StringProperty(name = "Mesh", - default = "", - description = "Target of Constraint - Mesh (optional, depends on type)") - active = bpy.props.BoolProperty(name = "Active", - default = True, - description = "Constraint is active") - baked = bpy.props.BoolProperty(name = "Baked / Applied", - default = False, - description = "Constraint has been baked to NLA layer") - targetFrame = bpy.props.IntProperty(name = "Frame", - default = 1, - description = "Target of Constraint - Frame (optional, depends on type)") - targetPoint = bpy.props.FloatVectorProperty(name = "Point", size = 3, - subtype = "XYZ", default = (0.0, 0.0, 0.0), - description = "Target of Constraint - Point") + name = bpy.props.StringProperty(name="Name", + default="Mocap Constraint", + description="Name of Mocap Constraint", + update=updateConstraint) + constrained_bone = bpy.props.StringProperty(name="Bone", + default="", + description="Constrained Bone", + update=updateConstraintTargetBone) + constrained_boneB = bpy.props.StringProperty(name="Bone (2)", + default="", + description="Other Constrained Bone (optional, depends on type)", + update=updateConstraint) + s_frame = bpy.props.IntProperty(name="S", + default=1, + description="Start frame of constraint", + update=updateConstraint) + e_frame = bpy.props.IntProperty(name="E", + default=500, + description="End frame of constrain", + update=updateConstraint) + targetMesh = bpy.props.StringProperty(name="Mesh", + default="", + description="Target of Constraint - Mesh (optional, depends on type)", + update=updateConstraint) + active = bpy.props.BoolProperty(name="Active", + default=True, + description="Constraint is active", + update=updateConstraint) + baked = bpy.props.BoolProperty(name="Baked / Applied", + default=False, + description="Constraint has been baked to NLA layer", + update=updateConstraint) + targetFrame = bpy.props.IntProperty(name="Frame", + default=1, + description="Target of Constraint - Frame (optional, depends on type)", + update=updateConstraint) + targetPoint = bpy.props.FloatVectorProperty(name="Point", size=3, + subtype="XYZ", default=(0.0, 0.0, 0.0), + description="Target of Constraint - Point", + update=updateConstraint) targetSpace = bpy.props.EnumProperty( - items = [("world", "World Space", "Evaluate target in global space"), + items=[("world", "World Space", "Evaluate target in global space"), ("object", "Object space", "Evaluate target in object space"), - ("boneb", "Other Bone Space", "Evaluate target in specified other bone space")], - name = "Space", - description = "In which space should Point type target be evaluated") + ("constrained_boneB", "Other Bone Space", "Evaluate target in specified other bone space")], + name="Space", + description="In which space should Point type target be evaluated", + update=updateConstraint) type = bpy.props.EnumProperty(name="Type of constraint", - items = [("point", "Maintain Position", "Bone is at a specific point"), + items=[("point", "Maintain Position", "Bone is at a specific point"), ("freeze", "Maintain Position at frame", "Bone does not move from location specified in target frame"), ("floor", "Stay above", "Bone does not cross specified mesh object eg floor"), ("distance", "Maintain distance", "Target bones maintained specified distance")], - description = "Type of constraint") - realConstraint = bpy.props.StringProperty() + description="Type of constraint", + update=updateConstraint) + real_constraint = bpy.props.StringProperty() + real_constraint_bone = bpy.props.StringProperty() bpy.utils.register_class(MocapConstraint) @@ -112,9 +123,9 @@ def toggleIKBone(self, context): bone.IKRetarget = False bpy.types.Bone.map = bpy.props.StringProperty() -bpy.types.PoseBone.IKRetarget = bpy.props.BoolProperty(name = "IK", - description = "Toggles IK Retargeting method for given bone", - update = toggleIKBone, default = False) +bpy.types.PoseBone.IKRetarget = bpy.props.BoolProperty(name="IK", + description="Toggles IK Retargeting method for given bone", + update=toggleIKBone, default=False) def hasIKConstraint(pose_bone): @@ -207,15 +218,15 @@ class MocapConstraintsPanel(bpy.types.Panel): if context.active_object.data.name in bpy.data.armatures: enduser_obj = context.active_object enduser_arm = enduser_obj.data - layout.operator("mocap.addconstraint", text = 'Add constraint') + layout.operator("mocap.addconstraint") layout.separator() for i, m_constraint in enumerate(enduser_arm.mocap_constraints): box = layout.box() box.prop(m_constraint, 'name') box.prop(m_constraint, 'type') - box.prop_search(m_constraint, 'boneA', enduser_obj.pose, "bones") + box.prop_search(m_constraint, 'constrained_bone', enduser_obj.pose, "bones") if m_constraint.type == "distance" or m_constraint.type == "point": - box.prop_search(m_constraint, 'boneB', enduser_obj.pose, "bones") + box.prop_search(m_constraint, 'constrained_boneB', enduser_obj.pose, "bones") frameRow = box.row() frameRow.label("Frame Range:") frameRow.prop(m_constraint, 's_frame') @@ -234,7 +245,7 @@ class MocapConstraintsPanel(bpy.types.Panel): checkRow = box.row() checkRow.prop(m_constraint, 'active') checkRow.prop(m_constraint, 'baked') - layout.operator("mocap.removeconstraint", text = "Remove constraint").constraint = i + layout.operator("mocap.removeconstraint", text="Remove constraint").constraint = i layout.separator() @@ -288,7 +299,7 @@ class OBJECT_OT_AddMocapConstraint(bpy.types.Operator): def execute(self, context): enduser_obj = bpy.context.active_object enduser_arm = enduser_obj.data - newCon = enduser_arm.mocap_constraints.add() + new_mcon = enduser_arm.mocap_constraints.add() return {"FINISHED"} @@ -300,8 +311,13 @@ class OBJECT_OT_RemoveMocapConstraint(bpy.types.Operator): def execute(self, context): enduser_obj = bpy.context.active_object enduser_arm = enduser_obj.data - constraints = enduser_arm.mocap_constraints - constraints.remove(self.constraint) + m_constraints = enduser_arm.mocap_constraints + m_constraint = m_constraints[self.constraint] + if m_constraint.real_constraint: + bone = enduser_obj.pose.bones[m_constraint.real_constraint_bone] + cons_obj = getConsObj(bone) + removeConstraint(m_constraint, cons_obj) + m_constraints.remove(self.constraint) return {"FINISHED"} @@ -312,6 +328,5 @@ def register(): def unregister(): bpy.utils.unregister_module(__name__) - if __name__ == "__main__": register() -- cgit v1.2.3 From 775ab37ad55daca119e6b59e693f3c9b77ca2ce2 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Sun, 3 Jul 2011 21:23:41 +0000 Subject: Fixed some issues with stride bone and original empty creation and parenting. Now there is no longer a constraint cycle issue when using IK constraints --- release/scripts/modules/retarget.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 3ce90f64075..64b9bb51eed 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -200,6 +200,8 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene): for t in range(s_frame, e_frame): scene.frame_set(t) end_bone = end_bones[root] + end_bone.location = Vector((0,0,0)) + end_bone.keyframe_insert("location") bakeTransform(end_bone) #recieves the performer feet bones as a variable @@ -207,7 +209,7 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene): # (they don't move, despite root moving) somewhere in the animation. -def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, root, s_frame, e_frame, scene): +def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, root, s_frame, e_frame, scene, enduser_obj_mat): endFeet = [bonemap[perfBone] for perfBone in perfFeet] perfRoot = bonemapr[root][0] locDictKeys = perfFeet + endFeet + [perfRoot] @@ -270,10 +272,12 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, roo if linearAvg: avg = sum(linearAvg) / len(linearAvg) + scene.frame_set(s_frame) + initialPos = (tailLoc(perf_bones[perfRoot]) / avg) for t in range(s_frame, e_frame): scene.frame_set(t) newTranslation = (tailLoc(perf_bones[perfRoot]) / avg) - stride_bone.location = newTranslation * enduser_obj.matrix_world + stride_bone.location = (newTranslation - initialPos) * enduser_obj_mat stride_bone.keyframe_insert("location") return stride_bone @@ -341,7 +345,7 @@ def restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, str for pose_bone in pose_bones: if pose_bone.name + "Org" in bpy.data.objects: empty = bpy.data.objects[pose_bone.name + "Org"] - empty.parent = enduser_obj + empty.parent = stride_bone performer_obj.matrix_world = perf_obj_mat enduser_obj.matrix_world = enduser_obj_mat @@ -364,7 +368,7 @@ def totalRetarget(): turnOffIK(enduser_obj) inter_obj, inter_arm = createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_frame, e_frame, scene) retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene) - stride_bone = copyTranslation(performer_obj, enduser_obj, ["RightFoot", "LeftFoot"], bonemap, bonemapr, root, s_frame, e_frame, scene) + stride_bone = copyTranslation(performer_obj, enduser_obj, ["RightFoot", "LeftFoot"], bonemap, bonemapr, root, s_frame, e_frame, scene,enduser_obj_mat) IKRetarget(bonemap, bonemapr, performer_obj, enduser_obj, s_frame, e_frame, scene) restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone) bpy.ops.object.mode_set(mode='OBJECT') @@ -372,4 +376,4 @@ def totalRetarget(): bpy.ops.object.delete() if __name__ == "__main__": - totalRetarget() + totalRetarget() \ No newline at end of file -- cgit v1.2.3 From e35806470408d01ddaf844c8ebd93fbc2cfdd68d Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Sun, 3 Jul 2011 21:25:54 +0000 Subject: Added smoothing variables to constraint creation, and now Active checkbox is functional.Also initial work was done on the freeze constraint. --- release/scripts/modules/mocap_constraints.py | 53 +++++++++++++++++++--------- release/scripts/startup/ui_mocap.py | 20 +++++++++-- 2 files changed, 53 insertions(+), 20 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py index 1251786d882..1892988c639 100644 --- a/release/scripts/modules/mocap_constraints.py +++ b/release/scripts/modules/mocap_constraints.py @@ -41,6 +41,12 @@ def getConsObj(bone): cons_obj = bone return cons_obj +def consObjToBone(cons_obj): + if cons_obj.name[-3:] == "Org": + return cons_obj.name[:-3] + else: + return cons_obj.name + ### And and Remove Constraints (called from operators) @@ -53,7 +59,7 @@ def addNewConstraint(m_constraint, cons_obj): c_type = "FLOOR" real_constraint = cons_obj.constraints.new(c_type) real_constraint.name = "Mocap constraint " + str(len(cons_obj.constraints)) - m_constraint.real_constraint_bone = cons_obj.name + m_constraint.real_constraint_bone = consObjToBone(cons_obj) m_constraint.real_constraint = real_constraint.name setConstraint(m_constraint) @@ -62,21 +68,14 @@ def removeConstraint(m_constraint, cons_obj): oldConstraint = cons_obj.constraints[m_constraint.real_constraint] cons_obj.constraints.remove(oldConstraint) -### Update functions. There are 3: UpdateType, UpdateBone +### Update functions. There are 2: UpdateType/UpdateBone ### and update for the others. def updateConstraint(self, context): setConstraint(self) - -def updateConstraintType(m_constraint, context): - pass - #If the constraint exists, we need to remove it - #Then create a new one. - - -def updateConstraintTargetBone(m_constraint, context): +def updateConstraintBoneType(m_constraint, context): #If the constraint exists, we need to remove it #from the old bone obj = context.active_object @@ -103,7 +102,10 @@ def setConstraint(m_constraint): real_constraint = cons_obj.constraints[m_constraint.real_constraint] #frame changing section - fcurves = obj.animation_data.action.fcurves + if isinstance(cons_obj, bpy.types.PoseBone): + fcurves = obj.animation_data.action.fcurves + else: + fcurves = cons_obj.animation_data.action.fcurves influence_RNA = real_constraint.path_from_id("influence") fcurve = [fcurve for fcurve in fcurves if fcurve.data_path == influence_RNA] #clear the fcurve and set the frames. @@ -111,17 +113,14 @@ def setConstraint(m_constraint): fcurve = fcurve[0] for i in range(len(fcurve.keyframe_points) - 1, 0, -1): fcurve.keyframe_points.remove(fcurve.keyframe_points[i]) - s, e = bpy.context.scene.frame_start, bpy.context.scene.frame_end - real_constraint.influence = 0 - real_constraint.keyframe_insert(data_path="influence", frame=s) - real_constraint.keyframe_insert(data_path="influence", frame=e) s, e = m_constraint.s_frame, m_constraint.e_frame + s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out real_constraint.influence = 1 real_constraint.keyframe_insert(data_path="influence", frame=s) real_constraint.keyframe_insert(data_path="influence", frame=e) real_constraint.influence = 0 - real_constraint.keyframe_insert(data_path="influence", frame=s - 10) - real_constraint.keyframe_insert(data_path="influence", frame=e + 10) + real_constraint.keyframe_insert(data_path="influence", frame=s - s_in) + real_constraint.keyframe_insert(data_path="influence", frame=e + s_out) #Set the blender constraint parameters if m_constraint.type == "point": @@ -139,3 +138,23 @@ def setConstraint(m_constraint): real_constraint.use_min_x = True real_constraint.use_min_y = True real_constraint.use_min_z = True + + if m_constraint.type == "freeze": + real_constraint.target_space = "WORLD" + bpy.context.scene.frame_set(m_constraint.s_frame) + x, y, z = cons_obj.location.copy() + real_constraint.max_x = x + real_constraint.max_y = y + real_constraint.max_z = z + real_constraint.min_x = x + real_constraint.min_y = y + real_constraint.min_z = z + real_constraint.use_max_x = True + real_constraint.use_max_y = True + real_constraint.use_max_z = True + real_constraint.use_min_x = True + real_constraint.use_min_y = True + real_constraint.use_min_z = True + + # active check + real_constraint.mute = not m_constraint.active \ No newline at end of file diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 4273eb74984..f4762f38c54 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -37,7 +37,7 @@ class MocapConstraint(bpy.types.PropertyGroup): constrained_bone = bpy.props.StringProperty(name="Bone", default="", description="Constrained Bone", - update=updateConstraintTargetBone) + update=updateConstraintBoneType) constrained_boneB = bpy.props.StringProperty(name="Bone (2)", default="", description="Other Constrained Bone (optional, depends on type)", @@ -50,6 +50,16 @@ class MocapConstraint(bpy.types.PropertyGroup): default=500, description="End frame of constrain", update=updateConstraint) + smooth_in = bpy.props.IntProperty(name="In", + default=10, + description="Amount of frames to smooth in", + update=updateConstraint, + min=0) + smooth_out = bpy.props.IntProperty(name="Out", + default=10, + description="Amount of frames to smooth out", + update=updateConstraint, + min=0) targetMesh = bpy.props.StringProperty(name="Mesh", default="", description="Target of Constraint - Mesh (optional, depends on type)", @@ -83,7 +93,7 @@ class MocapConstraint(bpy.types.PropertyGroup): ("floor", "Stay above", "Bone does not cross specified mesh object eg floor"), ("distance", "Maintain distance", "Target bones maintained specified distance")], description="Type of constraint", - update=updateConstraint) + update=updateConstraintBoneType) real_constraint = bpy.props.StringProperty() real_constraint_bone = bpy.props.StringProperty() @@ -231,6 +241,10 @@ class MocapConstraintsPanel(bpy.types.Panel): frameRow.label("Frame Range:") frameRow.prop(m_constraint, 's_frame') frameRow.prop(m_constraint, 'e_frame') + smoothRow = box.row() + smoothRow.label("Smoothing:") + smoothRow.prop(m_constraint, 'smooth_in') + smoothRow.prop(m_constraint, 'smooth_out') targetRow = box.row() targetLabelCol = targetRow.column() targetLabelCol.label("Target settings:") @@ -329,4 +343,4 @@ def unregister(): bpy.utils.unregister_module(__name__) if __name__ == "__main__": - register() + register() \ No newline at end of file -- cgit v1.2.3 From a552d8e6104db06d94e2a51d533d7f34cfd3aa47 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Mon, 4 Jul 2011 11:35:29 +0000 Subject: Finished Freeze constraint, and target space option for Freeze and Point constraints. --- release/scripts/modules/mocap_constraints.py | 24 ++++++++++++--------- release/scripts/modules/retarget.py | 1 + release/scripts/startup/ui_mocap.py | 32 ++++++++++++++++------------ 3 files changed, 33 insertions(+), 24 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py index 1892988c639..e12d510a6f9 100644 --- a/release/scripts/modules/mocap_constraints.py +++ b/release/scripts/modules/mocap_constraints.py @@ -23,7 +23,6 @@ from mathutils import * ### Utility Functions - def hasIKConstraint(pose_bone): #utility function / predicate, returns True if given bone has IK constraint return ("IK" in [constraint.type for constraint in pose_bone.constraints]) @@ -85,9 +84,10 @@ def updateConstraintBoneType(m_constraint, context): cons_obj = getConsObj(bone) removeConstraint(m_constraint, cons_obj) #Regardless, after that we create a new constraint - bone = bones[m_constraint.constrained_bone] - cons_obj = getConsObj(bone) - addNewConstraint(m_constraint, cons_obj) + if m_constraint.constrained_bone: + bone = bones[m_constraint.constrained_bone] + cons_obj = getConsObj(bone) + addNewConstraint(m_constraint, cons_obj) # Function that copies all settings from m_constraint to the real Blender constraints @@ -106,6 +106,7 @@ def setConstraint(m_constraint): fcurves = obj.animation_data.action.fcurves else: fcurves = cons_obj.animation_data.action.fcurves + influence_RNA = real_constraint.path_from_id("influence") fcurve = [fcurve for fcurve in fcurves if fcurve.data_path == influence_RNA] #clear the fcurve and set the frames. @@ -120,11 +121,10 @@ def setConstraint(m_constraint): real_constraint.keyframe_insert(data_path="influence", frame=e) real_constraint.influence = 0 real_constraint.keyframe_insert(data_path="influence", frame=s - s_in) - real_constraint.keyframe_insert(data_path="influence", frame=e + s_out) - + real_constraint.keyframe_insert(data_path="influence", frame=e + s_out) #Set the blender constraint parameters if m_constraint.type == "point": - real_constraint.target_space = "WORLD" # temporary for now, just World is supported + real_constraint.owner_space = m_constraint.targetSpace x, y, z = m_constraint.targetPoint real_constraint.max_x = x real_constraint.max_y = y @@ -140,9 +140,13 @@ def setConstraint(m_constraint): real_constraint.use_min_z = True if m_constraint.type == "freeze": - real_constraint.target_space = "WORLD" - bpy.context.scene.frame_set(m_constraint.s_frame) - x, y, z = cons_obj.location.copy() + real_constraint.owner_space = m_constraint.targetSpace + bpy.context.scene.frame_set(s) + if isinstance(cons_obj, bpy.types.PoseBone): + x, y, z = cons_obj.center + (cons_obj.vector / 2) + else: + x, y, z = cons_obj.matrix_world.to_translation() + real_constraint.max_x = x real_constraint.max_y = y real_constraint.max_z = z diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 64b9bb51eed..9a3ed4b70cb 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -348,6 +348,7 @@ def restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, str empty.parent = stride_bone performer_obj.matrix_world = perf_obj_mat enduser_obj.matrix_world = enduser_obj_mat + enduser_obj.parent = stride_bone def totalRetarget(): diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index f4762f38c54..71d291fd014 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -22,6 +22,15 @@ import bpy from bpy.props import * from bpy import * +import mocap_constraints +import retarget +import mocap_tools +### reloads modules (for testing purposes only) +from imp import reload +reload(mocap_constraints) +reload(retarget) +reload(mocap_tools) + from mocap_constraints import * # MocapConstraint class @@ -72,17 +81,13 @@ class MocapConstraint(bpy.types.PropertyGroup): default=False, description="Constraint has been baked to NLA layer", update=updateConstraint) - targetFrame = bpy.props.IntProperty(name="Frame", - default=1, - description="Target of Constraint - Frame (optional, depends on type)", - update=updateConstraint) targetPoint = bpy.props.FloatVectorProperty(name="Point", size=3, subtype="XYZ", default=(0.0, 0.0, 0.0), description="Target of Constraint - Point", update=updateConstraint) targetSpace = bpy.props.EnumProperty( - items=[("world", "World Space", "Evaluate target in global space"), - ("object", "Object space", "Evaluate target in object space"), + items=[("WORLD", "World Space", "Evaluate target in global space"), + ("LOCAL", "Object space", "Evaluate target in object space"), ("constrained_boneB", "Other Bone Space", "Evaluate target in specified other bone space")], name="Space", description="In which space should Point type target be evaluated", @@ -111,7 +116,11 @@ def toggleIKBone(self, context): print(self.name + " IK toggled ON!") ik = self.constraints.new('IK') #ik the whole chain up to the root, excluding - chainLen = len(self.bone.parent_recursive) + chainLen = 0 + for parent_bone in self.parent_recursive: + chainLen+=1 + if hasIKConstraint(parent_bone): + break ik.chain_count = chainLen for bone in self.parent_recursive: if bone.is_in_ik_chain: @@ -159,10 +168,6 @@ def updateIKRetarget(): updateIKRetarget() -import retarget -import mocap_tools - - class MocapPanel(bpy.types.Panel): # Motion capture retargeting panel bl_label = "Mocap tools" @@ -251,11 +256,10 @@ class MocapConstraintsPanel(bpy.types.Panel): targetPropCol = targetRow.column() if m_constraint.type == "floor": targetPropCol.prop_search(m_constraint, 'targetMesh', bpy.data, "objects") - if m_constraint.type == "freeze": - targetPropCol.prop(m_constraint, 'targetFrame') + if m_constraint.type == "point" or m_constraint.type == "freeze": + box.prop(m_constraint, 'targetSpace') if m_constraint.type == "point": targetPropCol.prop(m_constraint, 'targetPoint') - box.prop(m_constraint, 'targetSpace') checkRow = box.row() checkRow.prop(m_constraint, 'active') checkRow.prop(m_constraint, 'baked') -- cgit v1.2.3 From 90e8b83b45893619e4a666913afe6ea871a7d9d4 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Tue, 5 Jul 2011 10:55:35 +0000 Subject: Added denoising function. Uses a type of median filter to smooth out spikes, typical of sensor noise in motion capture data --- release/scripts/modules/mocap_tools.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'release') diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index dfb8aaf0eec..e9891bbf498 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -513,3 +513,37 @@ def fcurves_simplify(sel_opt="all", error=0.002, group_mode=True): print(str(totalt)[:5] + " seconds, total time elapsed") return + +# Implementation of non-linear median filter, with variable kernel size +# Double pass - one marks spikes, the other smooths one +# Expects sampled keyframes on everyframe + + +def denoise_median(): + context = bpy.context + obj = context.active_object + fcurves = obj.animation_data.action.fcurves + medKernel = 1 # actually *2+1... since it this is offset + flagKernel = 4 + highThres = (flagKernel * 2) - 1 + lowThres = 0 + for fcurve in fcurves: + orgPts = fcurve.keyframe_points[:] + flaggedFrames = [] + # mark frames that are spikes by sorting a large kernel + for i in range(flagKernel, len(fcurve.keyframe_points) - flagKernel): + center = orgPts[i] + neighborhood = orgPts[i - flagKernel: i + flagKernel] + neighborhood.sort(key=lambda pt: pt.co[1]) + weight = neighborhood.index(center) + if weight >= highThres or weight <= lowThres: + flaggedFrames.append((i, center)) + # clean marked frames with a simple median filter + # averages all frames in the kernel equally, except center which has no weight + for i, pt in flaggedFrames: + newValue = 0 + sumWeights = 0 + neighborhood = [neighpt.co[1] for neighpt in orgPts[i - medKernel: i + medKernel + 1] if neighpt != pt] + newValue = sum(neighborhood) / len(neighborhood) + pt.co[1] = newValue + return -- cgit v1.2.3 From 04c03db6af7fbcd3a574021d759917778deb7dc9 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Tue, 5 Jul 2011 10:56:34 +0000 Subject: Added One-Sided distance constraint. Also fixed some bugs and syntax in constraint and retarget scripts --- release/scripts/modules/mocap_constraints.py | 19 ++++++++++++++----- release/scripts/modules/retarget.py | 6 +++--- 2 files changed, 17 insertions(+), 8 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py index e12d510a6f9..4a7c22eb771 100644 --- a/release/scripts/modules/mocap_constraints.py +++ b/release/scripts/modules/mocap_constraints.py @@ -23,6 +23,7 @@ from mathutils import * ### Utility Functions + def hasIKConstraint(pose_bone): #utility function / predicate, returns True if given bone has IK constraint return ("IK" in [constraint.type for constraint in pose_bone.constraints]) @@ -40,6 +41,7 @@ def getConsObj(bone): cons_obj = bone return cons_obj + def consObjToBone(cons_obj): if cons_obj.name[-3:] == "Org": return cons_obj.name[:-3] @@ -74,6 +76,7 @@ def removeConstraint(m_constraint, cons_obj): def updateConstraint(self, context): setConstraint(self) + def updateConstraintBoneType(m_constraint, context): #If the constraint exists, we need to remove it #from the old bone @@ -106,7 +109,7 @@ def setConstraint(m_constraint): fcurves = obj.animation_data.action.fcurves else: fcurves = cons_obj.animation_data.action.fcurves - + influence_RNA = real_constraint.path_from_id("influence") fcurve = [fcurve for fcurve in fcurves if fcurve.data_path == influence_RNA] #clear the fcurve and set the frames. @@ -121,7 +124,7 @@ def setConstraint(m_constraint): real_constraint.keyframe_insert(data_path="influence", frame=e) real_constraint.influence = 0 real_constraint.keyframe_insert(data_path="influence", frame=s - s_in) - real_constraint.keyframe_insert(data_path="influence", frame=e + s_out) + real_constraint.keyframe_insert(data_path="influence", frame=e + s_out) #Set the blender constraint parameters if m_constraint.type == "point": real_constraint.owner_space = m_constraint.targetSpace @@ -140,7 +143,7 @@ def setConstraint(m_constraint): real_constraint.use_min_z = True if m_constraint.type == "freeze": - real_constraint.owner_space = m_constraint.targetSpace + real_constraint.owner_space = m_constraint.targetSpace bpy.context.scene.frame_set(s) if isinstance(cons_obj, bpy.types.PoseBone): x, y, z = cons_obj.center + (cons_obj.vector / 2) @@ -159,6 +162,12 @@ def setConstraint(m_constraint): real_constraint.use_min_x = True real_constraint.use_min_y = True real_constraint.use_min_z = True - + + if m_constraint.type == "distance" and m_constraint.constrained_boneB: + real_constraint.owner_space = "WORLD" + real_constraint.target = getConsObj(bones[m_constraint.constrained_boneB]) + real_constraint.limit_mode = "LIMITDIST_ONSURFACE" + real_constraint.distance = m_constraint.targetDist + # active check - real_constraint.mute = not m_constraint.active \ No newline at end of file + real_constraint.mute = not m_constraint.active diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 9a3ed4b70cb..b875b15e6e5 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -200,7 +200,7 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene): for t in range(s_frame, e_frame): scene.frame_set(t) end_bone = end_bones[root] - end_bone.location = Vector((0,0,0)) + end_bone.location = Vector((0, 0, 0)) end_bone.keyframe_insert("location") bakeTransform(end_bone) @@ -369,7 +369,7 @@ def totalRetarget(): turnOffIK(enduser_obj) inter_obj, inter_arm = createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_frame, e_frame, scene) retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene) - stride_bone = copyTranslation(performer_obj, enduser_obj, ["RightFoot", "LeftFoot"], bonemap, bonemapr, root, s_frame, e_frame, scene,enduser_obj_mat) + stride_bone = copyTranslation(performer_obj, enduser_obj, ["RightFoot", "LeftFoot"], bonemap, bonemapr, root, s_frame, e_frame, scene, enduser_obj_mat) IKRetarget(bonemap, bonemapr, performer_obj, enduser_obj, s_frame, e_frame, scene) restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone) bpy.ops.object.mode_set(mode='OBJECT') @@ -377,4 +377,4 @@ def totalRetarget(): bpy.ops.object.delete() if __name__ == "__main__": - totalRetarget() \ No newline at end of file + totalRetarget() -- cgit v1.2.3 From 887fd19894047832fbb7a7300e5fc11438b1f3b2 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Tue, 5 Jul 2011 10:57:29 +0000 Subject: Added access to denoising and new constraints functionality to UI script --- release/scripts/startup/ui_mocap.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 71d291fd014..e6c7529be99 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -85,6 +85,10 @@ class MocapConstraint(bpy.types.PropertyGroup): subtype="XYZ", default=(0.0, 0.0, 0.0), description="Target of Constraint - Point", update=updateConstraint) + targetDist = bpy.props.FloatProperty(name="Dist", + default=1, + description="Distance Constraint - Desired distance", + update=updateConstraint) targetSpace = bpy.props.EnumProperty( items=[("WORLD", "World Space", "Evaluate target in global space"), ("LOCAL", "Object space", "Evaluate target in object space"), @@ -118,9 +122,12 @@ def toggleIKBone(self, context): #ik the whole chain up to the root, excluding chainLen = 0 for parent_bone in self.parent_recursive: - chainLen+=1 + chainLen += 1 if hasIKConstraint(parent_bone): break + deformer_children = [child for child in parent_bone.children if child.bone.use_deform] + if len(deformer_children) > 1: + break ik.chain_count = chainLen for bone in self.parent_recursive: if bone.is_in_ik_chain: @@ -168,6 +175,7 @@ def updateIKRetarget(): updateIKRetarget() + class MocapPanel(bpy.types.Panel): # Motion capture retargeting panel bl_label = "Mocap tools" @@ -260,6 +268,8 @@ class MocapConstraintsPanel(bpy.types.Panel): box.prop(m_constraint, 'targetSpace') if m_constraint.type == "point": targetPropCol.prop(m_constraint, 'targetPoint') + if m_constraint.type == "distance": + targetPropCol.prop(m_constraint, 'targetDist') checkRow = box.row() checkRow.prop(m_constraint, 'active') checkRow.prop(m_constraint, 'baked') @@ -299,6 +309,7 @@ class OBJECT_OT_DenoiseButton(bpy.types.Operator): bl_label = "Denoises sampled mocap data " def execute(self, context): + mocap_tools.denoise_median() return {"FINISHED"} @@ -347,4 +358,4 @@ def unregister(): bpy.utils.unregister_module(__name__) if __name__ == "__main__": - register() \ No newline at end of file + register() -- cgit v1.2.3 From 89d7b9a0a6cdd0a2183a8e0f931f38c52303f848 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Wed, 6 Jul 2011 13:27:40 +0000 Subject: Added a small useful operator: Fix Armature Rotate. It fixes the common issue with mocap files that sometimes are rotated around the wrong axis --- release/scripts/modules/mocap_tools.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index e9891bbf498..fb48bac60c7 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -18,10 +18,10 @@ # -from math import hypot, sqrt, isfinite +from math import hypot, sqrt, isfinite, radians import bpy import time -from mathutils import Vector +from mathutils import Vector, Matrix #Vector utility functions @@ -547,3 +547,25 @@ def denoise_median(): newValue = sum(neighborhood) / len(neighborhood) pt.co[1] = newValue return + + +def rotate_fix_armature(arm_data): + global_matrix = Matrix.Rotation(radians(90),4,"X") + bpy.ops.object.mode_set(mode='EDIT', toggle=False) + if global_matrix!=Matrix(): #optimization: this might not be needed. + #disconnect all bones for ease of global rotation + connectedBones = [] + for bone in arm_data.edit_bones: + if bone.use_connect: + connectedBones.append(bone.name) + bone.use_connect=False + + #rotate all the bones around their center + for bone in arm_data.edit_bones: + bone.transform(global_matrix) + + #reconnect the bones + for bone in connectedBones: + arm_data.edit_bones[bone].use_connect=True + + bpy.ops.object.mode_set(mode='OBJECT', toggle=False) \ No newline at end of file -- cgit v1.2.3 From ebbcae36b32a3bcb7da800cabf447db109381fcc Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Wed, 6 Jul 2011 13:29:31 +0000 Subject: Coding style and cosmetic changes to mocap constraints module --- release/scripts/modules/mocap_constraints.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py index 4a7c22eb771..91ac87d8705 100644 --- a/release/scripts/modules/mocap_constraints.py +++ b/release/scripts/modules/mocap_constraints.py @@ -95,16 +95,8 @@ def updateConstraintBoneType(m_constraint, context): # Function that copies all settings from m_constraint to the real Blender constraints # Is only called when blender constraint already exists -def setConstraint(m_constraint): - if not m_constraint.constrained_bone: - return - obj = bpy.context.active_object - bones = obj.pose.bones - bone = bones[m_constraint.constrained_bone] - cons_obj = getConsObj(bone) - real_constraint = cons_obj.constraints[m_constraint.real_constraint] - #frame changing section +def setConstraintFraming(m_constraint, cons_obj): if isinstance(cons_obj, bpy.types.PoseBone): fcurves = obj.animation_data.action.fcurves else: @@ -125,6 +117,19 @@ def setConstraint(m_constraint): real_constraint.influence = 0 real_constraint.keyframe_insert(data_path="influence", frame=s - s_in) real_constraint.keyframe_insert(data_path="influence", frame=e + s_out) + +def setConstraint(m_constraint): + if not m_constraint.constrained_bone: + return + obj = bpy.context.active_object + bones = obj.pose.bones + bone = bones[m_constraint.constrained_bone] + cons_obj = getConsObj(bone) + real_constraint = cons_obj.constraints[m_constraint.real_constraint] + + #frame changing section + setConstraintFraming(m_constraint, cons_obj) + #Set the blender constraint parameters if m_constraint.type == "point": real_constraint.owner_space = m_constraint.targetSpace @@ -168,6 +173,7 @@ def setConstraint(m_constraint): real_constraint.target = getConsObj(bones[m_constraint.constrained_boneB]) real_constraint.limit_mode = "LIMITDIST_ONSURFACE" real_constraint.distance = m_constraint.targetDist + # active check real_constraint.mute = not m_constraint.active -- cgit v1.2.3 From 120e5a341729b6d74761ec4ec01f0691c9438e7f Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Wed, 6 Jul 2011 13:31:13 +0000 Subject: Cosmetic changes to UI. Also, added option to mark which bones should be planted when calculation new root translation (i.e. which bones are feet) --- release/scripts/modules/retarget.py | 25 ++++++++++++++++--------- release/scripts/startup/ui_mocap.py | 23 +++++++++++++++++++++-- 2 files changed, 37 insertions(+), 11 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index b875b15e6e5..dca3556f2c0 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -33,14 +33,15 @@ from math import radians, acos # be created from a more comfortable UI in the future -def createDictionary(perf_arm): +def createDictionary(perf_arm,end_arm): bonemap = {} + #Bonemap: performer to enduser for bone in perf_arm.bones: bonemap[bone.name] = bone.map - #root is the root of the enduser - root = "root" + # creation of a reverse map # multiple keys get mapped to list values + #Bonemapr: enduser to performer bonemapr = {} for key, value in bonemap.items(): if not value in bonemapr: @@ -51,7 +52,10 @@ def createDictionary(perf_arm): bonemapr[bonemap[key]] = [key] else: bonemapr[bonemap[key]].append(key) - return bonemap, bonemapr, root + #root is the root of the enduser + root = end_arm.bones[0].name + feetBones = [bone.name for bone in perf_arm.bones if bone.foot] + return bonemap, bonemapr, feetBones, root # list of empties created to keep track of "original" # position data # in final product, these locations can be stored as custom props @@ -210,12 +214,15 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene): def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, root, s_frame, e_frame, scene, enduser_obj_mat): - endFeet = [bonemap[perfBone] for perfBone in perfFeet] - perfRoot = bonemapr[root][0] - locDictKeys = perfFeet + endFeet + [perfRoot] + perf_bones = performer_obj.pose.bones end_bones = enduser_obj.pose.bones + perfRoot = bonemapr[root][0] + endFeet = [bonemap[perfBone] for perfBone in perfFeet] + locDictKeys = perfFeet + endFeet + [perfRoot] + + def tailLoc(bone): return bone.center + (bone.vector / 2) @@ -364,12 +371,12 @@ def totalRetarget(): scene = bpy.context.scene s_frame = scene.frame_start e_frame = scene.frame_end - bonemap, bonemapr, root = createDictionary(perf_arm) + bonemap, bonemapr, feetBones, root = createDictionary(perf_arm,end_arm) perf_obj_mat, enduser_obj_mat = cleanAndStoreObjMat(performer_obj, enduser_obj) turnOffIK(enduser_obj) inter_obj, inter_arm = createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_frame, e_frame, scene) retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene) - stride_bone = copyTranslation(performer_obj, enduser_obj, ["RightFoot", "LeftFoot"], bonemap, bonemapr, root, s_frame, e_frame, scene, enduser_obj_mat) + stride_bone = copyTranslation(performer_obj, enduser_obj, feetBones, bonemap, bonemapr, root, s_frame, e_frame, scene, enduser_obj_mat) IKRetarget(bonemap, bonemapr, performer_obj, enduser_obj, s_frame, e_frame, scene) restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone) bpy.ops.object.mode_set(mode='OBJECT') diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index e6c7529be99..737f3fcfa56 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -149,6 +149,9 @@ def toggleIKBone(self, context): bone.IKRetarget = False bpy.types.Bone.map = bpy.props.StringProperty() +bpy.types.Bone.foot = bpy.props.BoolProperty(name="Foot", + description="Marks this bone as a 'foot', which determines retargeted animation's translation", + default=False) bpy.types.PoseBone.IKRetarget = bpy.props.BoolProperty(name="IK", description="Toggles IK Retargeting method for given bone", update=toggleIKBone, default=False) @@ -189,6 +192,7 @@ class MocapPanel(bpy.types.Panel): row.alignment = 'EXPAND' row.operator("mocap.samples", text='Samples to Beziers') row.operator("mocap.denoise", text='Clean noise') + row.operator("mocap.rotate_fix", text='Fix BVH Axis Orientation') row2 = self.layout.row(align=True) row2.operator("mocap.looper", text='Loop animation') row2.operator("mocap.limitdof", text='Constrain Rig') @@ -198,7 +202,6 @@ class MocapPanel(bpy.types.Panel): column1.label("Performer Rig") column2 = row3.column(align=True) column2.label("Enduser Rig") - self.layout.label("Hierarchy mapping") enduser_obj = bpy.context.active_object performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj] if enduser_obj is None or len(performer_obj) != 1: @@ -212,6 +215,7 @@ class MocapPanel(bpy.types.Panel): perf_pose_bones = enduser_obj.pose.bones for bone in perf.bones: row = self.layout.row() + row.prop(data=bone, property='foot', text='', icon='POSE_DATA') row.label(bone.name) row.prop_search(bone, "map", enduser_arm, "bones") label_mod = "FK" @@ -222,7 +226,11 @@ class MocapPanel(bpy.types.Panel): if hasIKConstraint(pose_bone): label_mod = "ik end" row.prop(pose_bone, 'IKRetarget') - row.label(label_mod) + row.label(label_mod) + else: + row.label(" ") + row.label(" ") + self.layout.operator("mocap.retarget", text='RETARGET!') @@ -320,6 +328,17 @@ class OBJECT_OT_LimitDOFButton(bpy.types.Operator): def execute(self, context): return {"FINISHED"} +class OBJECT_OT_RotateFixArmature(bpy.types.Operator): + bl_idname = "mocap.rotate_fix" + bl_label = "Rotates selected armature 90 degrees (fix for bvh import)" + + def execute(self, context): + mocap_tools.rotate_fix_armature(context.active_object.data) + return {"FINISHED"} + + #def poll(self, context): + # return context.active_object.data in bpy.data.armatures + class OBJECT_OT_AddMocapConstraint(bpy.types.Operator): bl_idname = "mocap.addconstraint" -- cgit v1.2.3 From 236722010870dfeded84f331bff8a92b6a056e7c Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Wed, 6 Jul 2011 14:19:54 +0000 Subject: Changed creation of original location targets to be created only if needed for IK (i.e. user's decision) --- release/scripts/modules/retarget.py | 82 +++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 45 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index dca3556f2c0..6409c5ed535 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -33,12 +33,12 @@ from math import radians, acos # be created from a more comfortable UI in the future -def createDictionary(perf_arm,end_arm): +def createDictionary(perf_arm, end_arm): bonemap = {} #Bonemap: performer to enduser for bone in perf_arm.bones: bonemap[bone.name] = bone.map - + # creation of a reverse map # multiple keys get mapped to list values #Bonemapr: enduser to performer @@ -74,22 +74,6 @@ def createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_fr #the original position of the tail bone #useful for storing the important data in the original motion #i.e. using this empty to IK the chain to that pos / DEBUG - def locOfOriginal(inter_bone, perf_bone): - if not inter_bone.name + "Org" in bpy.data.objects: - bpy.ops.object.add() - empty = bpy.context.active_object - empty.name = inter_bone.name + "Org" - empty.empty_draw_size = 0.1 - #empty.parent = enduser_obj - empty = bpy.data.objects[inter_bone.name + "Org"] - offset = perf_bone.vector - if inter_bone.length == 0 or perf_bone.length == 0: - scaling = 1 - else: - scaling = perf_bone.length / inter_bone.length - offset /= scaling - empty.location = inter_bone.head + offset - empty.keyframe_insert("location") #Simple 1to1 retarget of a bone def singleBoneRetarget(inter_bone, perf_bone): @@ -116,21 +100,17 @@ def createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_fr perf_bone_name = bonemapr[inter_bone.name] #is it a 1 to many? if isinstance(bonemap[perf_bone_name[0]], tuple): - perf_bone = performer_bones[perf_bone_name[0]] - if inter_bone.name == bonemap[perf_bone_name[0]][0]: - locOfOriginal(inter_bone, perf_bone) + pass + # 1 to many not supported yet else: # then its either a many to 1 or 1 to 1 if len(perf_bone_name) > 1: performer_bones_s = [performer_bones[name] for name in perf_bone_name] #we need to map several performance bone to a single - for perf_bone in performer_bones_s: - locOfOriginal(inter_bone, perf_bone) inter_bone.matrix_basis = manyPerfToSingleInterRetarget(inter_bone, performer_bones_s) else: perf_bone = performer_bones[perf_bone_name[0]] - locOfOriginal(inter_bone, perf_bone) inter_bone.matrix_basis = singleBoneRetarget(inter_bone, perf_bone) inter_bone.keyframe_insert("rotation_quaternion") @@ -214,15 +194,14 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene): def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, root, s_frame, e_frame, scene, enduser_obj_mat): - + perf_bones = performer_obj.pose.bones end_bones = enduser_obj.pose.bones perfRoot = bonemapr[root][0] endFeet = [bonemap[perfBone] for perfBone in perfFeet] locDictKeys = perfFeet + endFeet + [perfRoot] - - + def tailLoc(bone): return bone.center + (bone.vector / 2) @@ -293,32 +272,34 @@ def IKRetarget(bonemap, bonemapr, performer_obj, enduser_obj, s_frame, e_frame, end_bones = enduser_obj.pose.bones for pose_bone in end_bones: if "IK" in [constraint.type for constraint in pose_bone.constraints]: + target_is_bone = False # set constraint target to corresponding empty if targetless, # if not, keyframe current target to corresponding empty perf_bone = bonemapr[pose_bone.name] if isinstance(perf_bone, list): perf_bone = bonemapr[pose_bone.name][-1] - end_empty = bpy.data.objects[pose_bone.name + "Org"] + orgLocTrg = originalLocationTarget(pose_bone) ik_constraint = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"][0] if not ik_constraint.target: - ik_constraint.target = end_empty + ik_constraint.target = orgLocTrg + target = orgLocTrg + + # There is a target now + if ik_constraint.subtarget: + target = ik_constraint.target.pose.bones[ik_constraint.subtarget] + target.bone.use_local_location = False + target_is_bone = True else: - #Bone target - target_is_bone = False - if ik_constraint.subtarget: - target = ik_constraint.target.pose.bones[ik_constraint.subtarget] - target.bone.use_local_location = False - target_is_bone = True + target = ik_constraint.target + + for t in range(s_frame, e_frame): + scene.frame_set(t) + if target_is_bone: + final_loc = pose_bone.tail - target.bone.matrix_local.to_translation() else: - target = ik_constraint.target - for t in range(s_frame, e_frame): - scene.frame_set(t) - if target_is_bone: - final_loc = end_empty.location - target.bone.matrix_local.to_translation() - else: - final_loc = end_empty.location - target.location = final_loc - target.keyframe_insert("location") + final_loc = pose_bone.tail + target.location = final_loc + target.keyframe_insert("location") ik_constraint.mute = False @@ -358,6 +339,17 @@ def restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, str enduser_obj.parent = stride_bone +def originalLocationTarget(end_bone): + if not end_bone.name + "Org" in bpy.data.objects: + bpy.ops.object.add() + empty = bpy.context.active_object + empty.name = end_bone.name + "Org" + empty.empty_draw_size = 0.1 + #empty.parent = enduser_obj + empty = bpy.data.objects[end_bone.name + "Org"] + return empty + + def totalRetarget(): print("retargeting...") enduser_obj = bpy.context.active_object @@ -371,7 +363,7 @@ def totalRetarget(): scene = bpy.context.scene s_frame = scene.frame_start e_frame = scene.frame_end - bonemap, bonemapr, feetBones, root = createDictionary(perf_arm,end_arm) + bonemap, bonemapr, feetBones, root = createDictionary(perf_arm, end_arm) perf_obj_mat, enduser_obj_mat = cleanAndStoreObjMat(performer_obj, enduser_obj) turnOffIK(enduser_obj) inter_obj, inter_arm = createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_frame, e_frame, scene) -- cgit v1.2.3 From eb6ac55e93527e12866f60cc8b8059b7705d6b5a Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Wed, 6 Jul 2011 14:20:38 +0000 Subject: pep8 compliance for python scripts --- release/scripts/modules/mocap_constraints.py | 10 ++++---- release/scripts/modules/mocap_tools.py | 34 +++++++++++++--------------- 2 files changed, 21 insertions(+), 23 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py index 91ac87d8705..ec587c987f6 100644 --- a/release/scripts/modules/mocap_constraints.py +++ b/release/scripts/modules/mocap_constraints.py @@ -96,7 +96,7 @@ def updateConstraintBoneType(m_constraint, context): # Function that copies all settings from m_constraint to the real Blender constraints # Is only called when blender constraint already exists -def setConstraintFraming(m_constraint, cons_obj): +def setConstraintFraming(m_constraint, cons_obj, real_constraint): if isinstance(cons_obj, bpy.types.PoseBone): fcurves = obj.animation_data.action.fcurves else: @@ -118,6 +118,7 @@ def setConstraintFraming(m_constraint, cons_obj): real_constraint.keyframe_insert(data_path="influence", frame=s - s_in) real_constraint.keyframe_insert(data_path="influence", frame=e + s_out) + def setConstraint(m_constraint): if not m_constraint.constrained_bone: return @@ -128,8 +129,8 @@ def setConstraint(m_constraint): real_constraint = cons_obj.constraints[m_constraint.real_constraint] #frame changing section - setConstraintFraming(m_constraint, cons_obj) - + setConstraintFraming(m_constraint, cons_obj, real_constraint) + #Set the blender constraint parameters if m_constraint.type == "point": real_constraint.owner_space = m_constraint.targetSpace @@ -149,7 +150,7 @@ def setConstraint(m_constraint): if m_constraint.type == "freeze": real_constraint.owner_space = m_constraint.targetSpace - bpy.context.scene.frame_set(s) + bpy.context.scene.frame_set(m_constraint.s_frame) if isinstance(cons_obj, bpy.types.PoseBone): x, y, z = cons_obj.center + (cons_obj.vector / 2) else: @@ -173,7 +174,6 @@ def setConstraint(m_constraint): real_constraint.target = getConsObj(bones[m_constraint.constrained_boneB]) real_constraint.limit_mode = "LIMITDIST_ONSURFACE" real_constraint.distance = m_constraint.targetDist - # active check real_constraint.mute = not m_constraint.active diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index fb48bac60c7..33e9105201c 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -550,22 +550,20 @@ def denoise_median(): def rotate_fix_armature(arm_data): - global_matrix = Matrix.Rotation(radians(90),4,"X") + global_matrix = Matrix.Rotation(radians(90), 4, "X") bpy.ops.object.mode_set(mode='EDIT', toggle=False) - if global_matrix!=Matrix(): #optimization: this might not be needed. - #disconnect all bones for ease of global rotation - connectedBones = [] - for bone in arm_data.edit_bones: - if bone.use_connect: - connectedBones.append(bone.name) - bone.use_connect=False - - #rotate all the bones around their center - for bone in arm_data.edit_bones: - bone.transform(global_matrix) - - #reconnect the bones - for bone in connectedBones: - arm_data.edit_bones[bone].use_connect=True - - bpy.ops.object.mode_set(mode='OBJECT', toggle=False) \ No newline at end of file + #disconnect all bones for ease of global rotation + connectedBones = [] + for bone in arm_data.edit_bones: + if bone.use_connect: + connectedBones.append(bone.name) + bone.use_connect = False + + #rotate all the bones around their center + for bone in arm_data.edit_bones: + bone.transform(global_matrix) + + #reconnect the bones + for bone in connectedBones: + arm_data.edit_bones[bone].use_connect = True + bpy.ops.object.mode_set(mode='OBJECT', toggle=False) -- cgit v1.2.3 From cff7c61ddbecf9b66a4d58d1237ffb100633efaa Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 7 Jul 2011 04:31:53 +0000 Subject: Patch [#23682] Add sort+move to bone group list in panel Thanks Torsten Rupp (rupp) for the patch! This patch adds the abilities to sort the bone group list in the properties panel and to move bone groups up/down in the list (similar like for vertex groups) --- .../startup/bl_ui/properties_data_armature.py | 23 ++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py index 9477dc866ab..217cd59f0de 100644 --- a/release/scripts/startup/bl_ui/properties_data_armature.py +++ b/release/scripts/startup/bl_ui/properties_data_armature.py @@ -96,6 +96,16 @@ class DATA_PT_display(ArmatureButtonsPanel, bpy.types.Panel): col.prop(arm, "use_deform_delay", text="Delay Refresh") +class DATA_PT_bone_group_specials(bpy.types.Menu): + bl_label = "Bone Group Specials" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + + def draw(self, context): + layout = self.layout + + layout.operator("pose.group_sort", icon='SORTALPHA') + + class DATA_PT_bone_groups(ArmatureButtonsPanel, bpy.types.Panel): bl_label = "Bone Groups" @@ -108,16 +118,25 @@ class DATA_PT_bone_groups(ArmatureButtonsPanel, bpy.types.Panel): ob = context.object pose = ob.pose + group = pose.bone_groups.active row = layout.row() - row.template_list(pose, "bone_groups", pose.bone_groups, "active_index", rows=2) + + rows = 2 + if group: + rows = 5 + row.template_list(pose, "bone_groups", pose.bone_groups, "active_index", rows=rows) col = row.column(align=True) col.active = (ob.proxy is None) col.operator("pose.group_add", icon='ZOOMIN', text="") col.operator("pose.group_remove", icon='ZOOMOUT', text="") + col.menu("DATA_PT_bone_group_specials", icon='DOWNARROW_HLT', text="") + if group: + col.separator() + col.operator("pose.group_move", icon='TRIA_UP', text="").direction = 'UP' + col.operator("pose.group_move", icon='TRIA_DOWN', text="").direction = 'DOWN' - group = pose.bone_groups.active if group: col = layout.column() col.active = (ob.proxy is None) -- cgit v1.2.3 From 5817f1347c7ed108d26731bc9275c4773ec865aa Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 7 Jul 2011 04:47:47 +0000 Subject: Remove unnecessary line from previous commit which slipped through --- release/scripts/startup/bl_ui/properties_data_armature.py | 1 - 1 file changed, 1 deletion(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py index 217cd59f0de..5d78dba33e7 100644 --- a/release/scripts/startup/bl_ui/properties_data_armature.py +++ b/release/scripts/startup/bl_ui/properties_data_armature.py @@ -98,7 +98,6 @@ class DATA_PT_display(ArmatureButtonsPanel, bpy.types.Panel): class DATA_PT_bone_group_specials(bpy.types.Menu): bl_label = "Bone Group Specials" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} def draw(self, context): layout = self.layout -- cgit v1.2.3 From 46f938e70b081d20da5dac2cbaca6900d9e9b2ad Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Thu, 7 Jul 2011 20:46:35 +0000 Subject: Added baking/unbaking functionality to constraint system. Retargeting now adds/manages 2 new NLA Tracks as planned. Modified bl_operatores/nla.py slightly to use it instead of creating my own bake function (now supports baking to a specific action, vs always creating a new one), but this does not break using the function in the old way. --- release/scripts/modules/mocap_constraints.py | 95 +++++++++++++++++++++++++++- release/scripts/modules/retarget.py | 15 +++++ release/scripts/startup/bl_operators/nla.py | 26 ++++---- release/scripts/startup/ui_mocap.py | 12 +--- 4 files changed, 124 insertions(+), 24 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py index ec587c987f6..07ebb01ea3d 100644 --- a/release/scripts/modules/mocap_constraints.py +++ b/release/scripts/modules/mocap_constraints.py @@ -20,6 +20,7 @@ import bpy from mathutils import * +from bl_operators import nla ### Utility Functions @@ -96,7 +97,7 @@ def updateConstraintBoneType(m_constraint, context): # Function that copies all settings from m_constraint to the real Blender constraints # Is only called when blender constraint already exists -def setConstraintFraming(m_constraint, cons_obj, real_constraint): +def setConstraintFraming(m_constraint, cons_obj, obj, real_constraint): if isinstance(cons_obj, bpy.types.PoseBone): fcurves = obj.animation_data.action.fcurves else: @@ -129,7 +130,7 @@ def setConstraint(m_constraint): real_constraint = cons_obj.constraints[m_constraint.real_constraint] #frame changing section - setConstraintFraming(m_constraint, cons_obj, real_constraint) + setConstraintFraming(m_constraint, cons_obj, obj, real_constraint) #Set the blender constraint parameters if m_constraint.type == "point": @@ -176,4 +177,92 @@ def setConstraint(m_constraint): real_constraint.distance = m_constraint.targetDist # active check - real_constraint.mute = not m_constraint.active + real_constraint.mute = (not m_constraint.active) and (m_constraint.baked) + + +def updateBake(self, context): + if self.baked: + print("baking...") + bakeConstraint(self) + else: + print("unbaking...") + unbakeConstraint(self) + + +def bakeTransformFK(anim_data, s_frame, e_frame, end_bone, bones, cons_obj): + mute_ik = False + for bone in bones: + bone.bone.select = False + ik = hasIKConstraint(end_bone) + if not isinstance(cons_obj, bpy.types.PoseBone) and ik: + if ik.chain_count == 0: + selectedBones = bones + else: + selectedBones = [end_bone] + end_bone.parent_recursive[:ik.chain_count - 1] + mute_ik = True + else: + selectedBones = [end_bone] + print(selectedBones) + for bone in selectedBones: + bone.bone.select = True + anim_data.action = nla.bake(s_frame, + e_frame, action=anim_data.action) + return mute_ik + + +def bakeConstraint(m_constraint): + obj = bpy.context.active_object + bones = obj.pose.bones + end_bone = bones[m_constraint.constrained_bone] + cons_obj = getConsObj(end_bone) + scene = bpy.context.scene + s_frame = scene.frame_start + e_frame = scene.frame_end + mute_ik = bakeTransformFK(obj.animation_data, s_frame, e_frame, end_bone, bones, cons_obj) + if mute_ik: + ik_con = hasIKConstraint(end_bone) + ik_con.mute = True + real_constraint = cons_obj.constraints[m_constraint.real_constraint] + real_constraint.mute = True + constraintTrack = obj.animation_data.nla_tracks["Mocap constraints"] + constraintStrip = constraintTrack.strips[0] + constraintStrip.action_frame_start = s_frame + constraintStrip.action_frame_end = e_frame + constraintStrip.frame_start = s_frame + constraintStrip.frame_end = e_frame + + +def unbakeConstraint(m_constraint): + # to unbake a constraint we need to delete the whole strip + # and rebake all the other constraints + obj = bpy.context.active_object + bones = obj.pose.bones + end_bone = bones[m_constraint.constrained_bone] + cons_obj = getConsObj(end_bone) + scene = bpy.context.scene + s_frame = scene.frame_start + e_frame = scene.frame_end + constraintTrack = obj.animation_data.nla_tracks["Mocap constraints"] + constraintStrip = constraintTrack.strips[0] + action = constraintStrip.action + for fcurve in action.fcurves: + action.fcurves.remove(fcurve) + for other_m_constraint in obj.data.mocap_constraints: + if m_constraint != other_m_constraint: + bakeConstraint(other_m_constraint) + # It's a control empty: turn the ik back on + if not isinstance(cons_obj, bpy.types.PoseBone): + ik_con = hasIKConstraint(end_bone) + if ik_con: + ik_con.mute = False + real_constraint = cons_obj.constraints[m_constraint.real_constraint] + real_constraint.mute = False + + +def hasIKConstraint(pose_bone): + #utility function / predicate, returns True if given bone has IK constraint + ik = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"] + if ik: + return ik[0] + else: + return False diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 6409c5ed535..885a457061a 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -374,6 +374,21 @@ def totalRetarget(): bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_name(name=inter_obj.name, extend=False) bpy.ops.object.delete() + anim_data = enduser_obj.animation_data + mocapAction = anim_data.action + mocapAction.name = "Base Mocap Action" + anim_data.use_nla = True + mocapTrack = anim_data.nla_tracks.new() + mocapTrack.name = "Base Mocap Track" + mocapStrip = mocapTrack.strips.new("Base Mocap Action", s_frame, mocapAction) + constraintTrack = anim_data.nla_tracks.new() + constraintTrack.name = "Mocap constraints" + constraintAction = bpy.data.actions.new("Mocap constraints Action") + constraintStrip = constraintTrack.strips.new("Mocap constraints Action", s_frame, constraintAction) + #constraintStrip.frame_end = e_frame + anim_data.nla_tracks.active = constraintTrack + anim_data.action = constraintAction + if __name__ == "__main__": totalRetarget() diff --git a/release/scripts/startup/bl_operators/nla.py b/release/scripts/startup/bl_operators/nla.py index 7a5fa552ede..e0b5a11dc78 100644 --- a/release/scripts/startup/bl_operators/nla.py +++ b/release/scripts/startup/bl_operators/nla.py @@ -83,7 +83,7 @@ def bake(frame_start, do_pose=True, do_object=True, do_constraint_clear=False, - ): + action=None): scene = bpy.context.scene obj = bpy.context.object @@ -120,7 +120,8 @@ def bake(frame_start, # incase animation data hassnt been created atd = obj.animation_data_create() - action = bpy.data.actions.new("Action") + if action == None: + action = bpy.data.actions.new("Action") atd.action = action if do_pose: @@ -253,37 +254,38 @@ class BakeAction(bpy.types.Operator): def invoke(self, context, event): wm = context.window_manager return wm.invoke_props_dialog(self) - + ################################# + class ClearUselessActions(bpy.types.Operator): '''Mark actions with no F-Curves for deletion after save+reload of file preserving "action libraries"''' bl_idname = "anim.clear_useless_actions" bl_label = "Clear Useless Actions" bl_options = {'REGISTER', 'UNDO'} - - only_unused = BoolProperty(name="Only Unused", + + only_unused = BoolProperty(name="Only Unused", description="Only unused (Fake User only) actions get considered", default=True) - + @classmethod def poll(cls, context): return len(bpy.data.actions) != 0 - + def execute(self, context): removed = 0 - + for action in bpy.data.actions: # if only user is "fake" user... - if ((self.only_unused is False) or + if ((self.only_unused is False) or (action.use_fake_user and action.users == 1)): - - # if it has F-Curves, then it's a "action library" (i.e. walk, wave, jump, etc.) + + # if it has F-Curves, then it's a "action library" (i.e. walk, wave, jump, etc.) # and should be left alone as that's what fake users are for! if not action.fcurves: # mark action for deletion action.user_clear() removed += 1 - + self.report({'INFO'}, "Removed %d empty and/or fake-user only Actions" % (removed)) return {'FINISHED'} diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 737f3fcfa56..d750489191f 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -80,7 +80,7 @@ class MocapConstraint(bpy.types.PropertyGroup): baked = bpy.props.BoolProperty(name="Baked / Applied", default=False, description="Constraint has been baked to NLA layer", - update=updateConstraint) + update=updateBake) targetPoint = bpy.props.FloatVectorProperty(name="Point", size=3, subtype="XYZ", default=(0.0, 0.0, 0.0), description="Target of Constraint - Point", @@ -157,11 +157,6 @@ bpy.types.PoseBone.IKRetarget = bpy.props.BoolProperty(name="IK", update=toggleIKBone, default=False) -def hasIKConstraint(pose_bone): - #utility function / predicate, returns True if given bone has IK constraint - return ("IK" in [constraint.type for constraint in pose_bone.constraints]) - - def updateIKRetarget(): # ensures that Blender constraints and IK properties are in sync # currently runs when module is loaded, should run when scene is loaded @@ -230,8 +225,6 @@ class MocapPanel(bpy.types.Panel): else: row.label(" ") row.label(" ") - - self.layout.operator("mocap.retarget", text='RETARGET!') @@ -328,6 +321,7 @@ class OBJECT_OT_LimitDOFButton(bpy.types.Operator): def execute(self, context): return {"FINISHED"} + class OBJECT_OT_RotateFixArmature(bpy.types.Operator): bl_idname = "mocap.rotate_fix" bl_label = "Rotates selected armature 90 degrees (fix for bvh import)" @@ -335,7 +329,7 @@ class OBJECT_OT_RotateFixArmature(bpy.types.Operator): def execute(self, context): mocap_tools.rotate_fix_armature(context.active_object.data) return {"FINISHED"} - + #def poll(self, context): # return context.active_object.data in bpy.data.armatures -- cgit v1.2.3 From c749a42a8ed77805cf39f9debb508f13313429f9 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Sat, 9 Jul 2011 21:52:25 +0000 Subject: Some optimizations and coding style improvements across the retargeting and constraint scripts --- release/scripts/modules/mocap_constraints.py | 87 +++++++------- release/scripts/modules/retarget.py | 162 ++++++++++++--------------- release/scripts/startup/ui_mocap.py | 114 ++++++++++++++++--- 3 files changed, 211 insertions(+), 152 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py index 07ebb01ea3d..f4d96d6a5d0 100644 --- a/release/scripts/modules/mocap_constraints.py +++ b/release/scripts/modules/mocap_constraints.py @@ -21,15 +21,11 @@ import bpy from mathutils import * from bl_operators import nla +from retarget import hasIKConstraint ### Utility Functions -def hasIKConstraint(pose_bone): - #utility function / predicate, returns True if given bone has IK constraint - return ("IK" in [constraint.type for constraint in pose_bone.constraints]) - - def getConsObj(bone): #utility function - returns related IK target if bone has IK ik = [constraint for constraint in bone.constraints if constraint.type == "IK"] @@ -63,21 +59,18 @@ def addNewConstraint(m_constraint, cons_obj): real_constraint.name = "Mocap constraint " + str(len(cons_obj.constraints)) m_constraint.real_constraint_bone = consObjToBone(cons_obj) m_constraint.real_constraint = real_constraint.name - setConstraint(m_constraint) + setConstraint(m_constraint, bpy.context) def removeConstraint(m_constraint, cons_obj): oldConstraint = cons_obj.constraints[m_constraint.real_constraint] + removeInfluenceFcurve(cons_obj, bpy.context.active_object, oldConstraint) cons_obj.constraints.remove(oldConstraint) ### Update functions. There are 2: UpdateType/UpdateBone ### and update for the others. -def updateConstraint(self, context): - setConstraint(self) - - def updateConstraintBoneType(m_constraint, context): #If the constraint exists, we need to remove it #from the old bone @@ -94,10 +87,24 @@ def updateConstraintBoneType(m_constraint, context): addNewConstraint(m_constraint, cons_obj) -# Function that copies all settings from m_constraint to the real Blender constraints -# Is only called when blender constraint already exists +def setConstraintFraming(m_constraint, context): + obj = context.active_object + bones = obj.pose.bones + bone = bones[m_constraint.constrained_bone] + cons_obj = getConsObj(bone) + real_constraint = cons_obj.constraints[m_constraint.real_constraint] + removeInfluenceFcurve(cons_obj, obj, real_constraint) + s, e = m_constraint.s_frame, m_constraint.e_frame + s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out + real_constraint.influence = 1 + real_constraint.keyframe_insert(data_path="influence", frame=s) + real_constraint.keyframe_insert(data_path="influence", frame=e) + real_constraint.influence = 0 + real_constraint.keyframe_insert(data_path="influence", frame=s - s_in) + real_constraint.keyframe_insert(data_path="influence", frame=e + s_out) -def setConstraintFraming(m_constraint, cons_obj, obj, real_constraint): + +def removeInfluenceFcurve(cons_obj, obj, real_constraint): if isinstance(cons_obj, bpy.types.PoseBone): fcurves = obj.animation_data.action.fcurves else: @@ -107,30 +114,24 @@ def setConstraintFraming(m_constraint, cons_obj, obj, real_constraint): fcurve = [fcurve for fcurve in fcurves if fcurve.data_path == influence_RNA] #clear the fcurve and set the frames. if fcurve: - fcurve = fcurve[0] - for i in range(len(fcurve.keyframe_points) - 1, 0, -1): - fcurve.keyframe_points.remove(fcurve.keyframe_points[i]) - s, e = m_constraint.s_frame, m_constraint.e_frame - s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out - real_constraint.influence = 1 - real_constraint.keyframe_insert(data_path="influence", frame=s) - real_constraint.keyframe_insert(data_path="influence", frame=e) - real_constraint.influence = 0 - real_constraint.keyframe_insert(data_path="influence", frame=s - s_in) - real_constraint.keyframe_insert(data_path="influence", frame=e + s_out) + fcurves.remove(fcurve[0]) + + +# Function that copies all settings from m_constraint to the real Blender constraints +# Is only called when blender constraint already exists -def setConstraint(m_constraint): +def setConstraint(m_constraint, context): if not m_constraint.constrained_bone: return - obj = bpy.context.active_object + obj = context.active_object bones = obj.pose.bones bone = bones[m_constraint.constrained_bone] cons_obj = getConsObj(bone) real_constraint = cons_obj.constraints[m_constraint.real_constraint] #frame changing section - setConstraintFraming(m_constraint, cons_obj, obj, real_constraint) + #setConstraintFraming(m_constraint, cons_obj, obj, real_constraint) #Set the blender constraint parameters if m_constraint.type == "point": @@ -176,17 +177,17 @@ def setConstraint(m_constraint): real_constraint.limit_mode = "LIMITDIST_ONSURFACE" real_constraint.distance = m_constraint.targetDist - # active check + # active/baked check real_constraint.mute = (not m_constraint.active) and (m_constraint.baked) def updateBake(self, context): if self.baked: print("baking...") - bakeConstraint(self) + bakeConstraint(self, context) else: print("unbaking...") - unbakeConstraint(self) + unbakeConstraint(self, context) def bakeTransformFK(anim_data, s_frame, e_frame, end_bone, bones, cons_obj): @@ -210,14 +211,15 @@ def bakeTransformFK(anim_data, s_frame, e_frame, end_bone, bones, cons_obj): return mute_ik -def bakeConstraint(m_constraint): - obj = bpy.context.active_object +def bakeConstraint(m_constraint, context): + obj = context.active_object bones = obj.pose.bones end_bone = bones[m_constraint.constrained_bone] cons_obj = getConsObj(end_bone) - scene = bpy.context.scene - s_frame = scene.frame_start - e_frame = scene.frame_end + s, e = m_constraint.s_frame, m_constraint.e_frame + s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out + s_frame = s - s_in + e_frame = e + s_out mute_ik = bakeTransformFK(obj.animation_data, s_frame, e_frame, end_bone, bones, cons_obj) if mute_ik: ik_con = hasIKConstraint(end_bone) @@ -232,16 +234,14 @@ def bakeConstraint(m_constraint): constraintStrip.frame_end = e_frame -def unbakeConstraint(m_constraint): +def unbakeConstraint(m_constraint, context): # to unbake a constraint we need to delete the whole strip # and rebake all the other constraints - obj = bpy.context.active_object + obj = context.active_object bones = obj.pose.bones end_bone = bones[m_constraint.constrained_bone] cons_obj = getConsObj(end_bone) scene = bpy.context.scene - s_frame = scene.frame_start - e_frame = scene.frame_end constraintTrack = obj.animation_data.nla_tracks["Mocap constraints"] constraintStrip = constraintTrack.strips[0] action = constraintStrip.action @@ -257,12 +257,3 @@ def unbakeConstraint(m_constraint): ik_con.mute = False real_constraint = cons_obj.constraints[m_constraint.real_constraint] real_constraint.mute = False - - -def hasIKConstraint(pose_bone): - #utility function / predicate, returns True if given bone has IK constraint - ik = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"] - if ik: - return ik[0] - else: - return False diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 885a457061a..ef1bc7a1488 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -22,40 +22,33 @@ import bpy from mathutils import * from math import radians, acos -#TODO: Only selected bones get retargeted. -# Selected Bones/chains get original pos empties, -# if ppl want IK instead of FK -# Some "magic" numbers - frame start and end, -# eulers of all orders instead of just quats keyframed -# dictionary of mapping -# this is currently manuall input'ed, but willW -# be created from a more comfortable UI in the future +def hasIKConstraint(pose_bone): + #utility function / predicate, returns True if given bone has IK constraint + ik = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"] + if ik: + return ik[0] + else: + return False def createDictionary(perf_arm, end_arm): - bonemap = {} - #Bonemap: performer to enduser - for bone in perf_arm.bones: - bonemap[bone.name] = bone.map - - # creation of a reverse map - # multiple keys get mapped to list values - #Bonemapr: enduser to performer - bonemapr = {} - for key, value in bonemap.items(): - if not value in bonemapr: - if isinstance(bonemap[key], tuple): - for key_x in bonemap[key]: - bonemapr[key_x] = [key] - else: - bonemapr[bonemap[key]] = [key] - else: - bonemapr[bonemap[key]].append(key) + # clear any old data + for end_bone in end_arm.bones: + for mapping in end_bone.reverseMap: + end_bone.reverseMap.remove(0) + + for perf_bone in perf_arm.bones: + #find its match and add perf_bone to the match's mapping + if perf_bone.map: + end_bone = end_arm.bones[perf_bone.map] + newMap = end_bone.reverseMap.add() + newMap.name = perf_bone.name + #root is the root of the enduser root = end_arm.bones[0].name feetBones = [bone.name for bone in perf_arm.bones if bone.foot] - return bonemap, bonemapr, feetBones, root + return feetBones, root # list of empties created to keep track of "original" # position data # in final product, these locations can be stored as custom props @@ -69,7 +62,7 @@ def createDictionary(perf_arm, end_arm): # easily while concentrating on the hierarchy changes -def createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_frame, e_frame, scene): +def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene): #creates and keyframes an empty with its location #the original position of the tail bone #useful for storing the important data in the original motion @@ -96,22 +89,17 @@ def createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_fr #determines the type of hierachy change needed and calls the #right function def retargetPerfToInter(inter_bone): - if inter_bone.name in bonemapr: - perf_bone_name = bonemapr[inter_bone.name] - #is it a 1 to many? - if isinstance(bonemap[perf_bone_name[0]], tuple): - pass + if inter_bone.bone.reverseMap: + perf_bone_name = inter_bone.bone.reverseMap # 1 to many not supported yet - else: # then its either a many to 1 or 1 to 1 - - if len(perf_bone_name) > 1: - performer_bones_s = [performer_bones[name] for name in perf_bone_name] - #we need to map several performance bone to a single - inter_bone.matrix_basis = manyPerfToSingleInterRetarget(inter_bone, performer_bones_s) - else: - perf_bone = performer_bones[perf_bone_name[0]] - inter_bone.matrix_basis = singleBoneRetarget(inter_bone, perf_bone) + if len(perf_bone_name) > 1: + performer_bones_s = [performer_bones[map.name] for map in perf_bone_name] + #we need to map several performance bone to a single + inter_bone.matrix_basis = manyPerfToSingleInterRetarget(inter_bone, performer_bones_s) + else: + perf_bone = performer_bones[perf_bone_name[0].name] + inter_bone.matrix_basis = singleBoneRetarget(inter_bone, perf_bone) inter_bone.keyframe_insert("rotation_quaternion") for child in inter_bone.children: @@ -140,7 +128,7 @@ def createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_fr inter_bone = inter_bones[root] retargetPerfToInter(inter_bone) - return inter_obj, inter_arm + return inter_obj # this procedure copies the rotations over from the intermediate # armature to the end user one. @@ -176,7 +164,13 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene): rest_matrix_inv.invert() bake_matrix = rest_matrix_inv * bake_matrix trg_bone.matrix_basis = bake_matrix - end_bone.keyframe_insert("rotation_quaternion") + rot_mode = end_bone.rotation_mode + if rot_mode == "QUATERNION": + end_bone.keyframe_insert("rotation_quaternion") + elif rot_mode == "AXIS_ANGLE": + end_bone.keyframe_insert("rotation_axis_angle") + else: + end_bone.keyframe_insert("rotation_euler") for bone in end_bone.children: bakeTransform(bone) @@ -193,13 +187,13 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene): # (they don't move, despite root moving) somewhere in the animation. -def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, root, s_frame, e_frame, scene, enduser_obj_mat): +def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame, scene, enduser_obj_mat): perf_bones = performer_obj.pose.bones end_bones = enduser_obj.pose.bones - perfRoot = bonemapr[root][0] - endFeet = [bonemap[perfBone] for perfBone in perfFeet] + perfRoot = end_bones[root].bone.reverseMap[0].name + endFeet = [perf_bones[perfBone].bone.map for perfBone in perfFeet] locDictKeys = perfFeet + endFeet + [perfRoot] def tailLoc(bone): @@ -208,7 +202,7 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, roo #Step 1 - we create a dict that contains these keys: #(Performer) Hips, Feet #(End user) Feet - # where the values are their world position on each (1,120) frame + # where the values are their world position on each frame in range (s,e) locDict = {} for key in locDictKeys: @@ -231,10 +225,7 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, roo for key in locDict.keys(): graph = locDict[key] - for t in range(len(graph) - 1): - x = graph[t] - xh = graph[t + 1] - locDeriv[key].append(xh - x) + locDeriv[key] = [graph[t + 1] - graph[t] for t in range(len(graph) - 1)] # now find the plant frames, where perfFeet don't move much @@ -244,7 +235,7 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, roo for i in range(len(locDeriv[key]) - 1): v = locDeriv[key][i] hipV = locDeriv[perfRoot][i] - endV = locDeriv[bonemap[key]][i] + endV = locDeriv[perf_bones[key].bone.map][i] if (v.length < 0.1): #this is a plant frame. #lets see what the original hip delta is, and the corresponding @@ -268,18 +259,16 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, roo return stride_bone -def IKRetarget(bonemap, bonemapr, performer_obj, enduser_obj, s_frame, e_frame, scene): +def IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene): end_bones = enduser_obj.pose.bones for pose_bone in end_bones: - if "IK" in [constraint.type for constraint in pose_bone.constraints]: + ik_constraint = hasIKConstraint(pose_bone) + if ik_constraint: target_is_bone = False # set constraint target to corresponding empty if targetless, # if not, keyframe current target to corresponding empty - perf_bone = bonemapr[pose_bone.name] - if isinstance(perf_bone, list): - perf_bone = bonemapr[pose_bone.name][-1] + perf_bone = pose_bone.bone.reverseMap[-1].name orgLocTrg = originalLocationTarget(pose_bone) - ik_constraint = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"][0] if not ik_constraint.target: ik_constraint.target = orgLocTrg target = orgLocTrg @@ -314,8 +303,8 @@ def turnOffIK(enduser_obj): #pose_bone.ik_stiffness_x = 0.5 #pose_bone.ik_stiffness_y = 0.5 #pose_bone.ik_stiffness_z = 0.5 - if "IK" in [constraint.type for constraint in pose_bone.constraints]: - ik_constraint = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"][0] + ik_constraint = hasIKConstraint(pose_bone) + if ik_constraint: ik_constraint.mute = True @@ -350,45 +339,38 @@ def originalLocationTarget(end_bone): return empty -def totalRetarget(): - print("retargeting...") - enduser_obj = bpy.context.active_object - performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj] - if enduser_obj is None or len(performer_obj) != 1: - print("Need active and selected armatures") - else: - performer_obj = performer_obj[0] - perf_arm = performer_obj.data - end_arm = enduser_obj.data - scene = bpy.context.scene - s_frame = scene.frame_start - e_frame = scene.frame_end - bonemap, bonemapr, feetBones, root = createDictionary(perf_arm, end_arm) - perf_obj_mat, enduser_obj_mat = cleanAndStoreObjMat(performer_obj, enduser_obj) - turnOffIK(enduser_obj) - inter_obj, inter_arm = createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_frame, e_frame, scene) - retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene) - stride_bone = copyTranslation(performer_obj, enduser_obj, feetBones, bonemap, bonemapr, root, s_frame, e_frame, scene, enduser_obj_mat) - IKRetarget(bonemap, bonemapr, performer_obj, enduser_obj, s_frame, e_frame, scene) - restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone) - bpy.ops.object.mode_set(mode='OBJECT') - bpy.ops.object.select_name(name=inter_obj.name, extend=False) - bpy.ops.object.delete() +def NLASystemInitialize(enduser_obj, s_frame): anim_data = enduser_obj.animation_data mocapAction = anim_data.action - mocapAction.name = "Base Mocap Action" + mocapAction.name = "Base Mocap" anim_data.use_nla = True mocapTrack = anim_data.nla_tracks.new() mocapTrack.name = "Base Mocap Track" - mocapStrip = mocapTrack.strips.new("Base Mocap Action", s_frame, mocapAction) + mocapStrip = mocapTrack.strips.new("Base Mocap", s_frame, mocapAction) constraintTrack = anim_data.nla_tracks.new() constraintTrack.name = "Mocap constraints" - constraintAction = bpy.data.actions.new("Mocap constraints Action") - constraintStrip = constraintTrack.strips.new("Mocap constraints Action", s_frame, constraintAction) - #constraintStrip.frame_end = e_frame + constraintAction = bpy.data.actions.new("Mocap constraints") + constraintStrip = constraintTrack.strips.new("Mocap constraints", s_frame, constraintAction) anim_data.nla_tracks.active = constraintTrack anim_data.action = constraintAction +def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): + perf_arm = performer_obj.data + end_arm = enduser_obj.data + feetBones, root = createDictionary(perf_arm, end_arm) + perf_obj_mat, enduser_obj_mat = cleanAndStoreObjMat(performer_obj, enduser_obj) + turnOffIK(enduser_obj) + inter_obj = createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene) + retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene) + stride_bone = copyTranslation(performer_obj, enduser_obj, feetBones, root, s_frame, e_frame, scene, enduser_obj_mat) + IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene) + restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone) + bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.object.select_name(name=inter_obj.name, extend=False) + bpy.ops.object.delete() + NLASystemInitialize(enduser_obj, s_frame) + + if __name__ == "__main__": totalRetarget() diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index d750489191f..b09f9705a56 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -42,7 +42,7 @@ class MocapConstraint(bpy.types.PropertyGroup): name = bpy.props.StringProperty(name="Name", default="Mocap Constraint", description="Name of Mocap Constraint", - update=updateConstraint) + update=setConstraint) constrained_bone = bpy.props.StringProperty(name="Bone", default="", description="Constrained Bone", @@ -50,33 +50,33 @@ class MocapConstraint(bpy.types.PropertyGroup): constrained_boneB = bpy.props.StringProperty(name="Bone (2)", default="", description="Other Constrained Bone (optional, depends on type)", - update=updateConstraint) + update=setConstraint) s_frame = bpy.props.IntProperty(name="S", default=1, description="Start frame of constraint", - update=updateConstraint) + update=setConstraintFraming) e_frame = bpy.props.IntProperty(name="E", default=500, description="End frame of constrain", - update=updateConstraint) + update=setConstraintFraming) smooth_in = bpy.props.IntProperty(name="In", default=10, description="Amount of frames to smooth in", - update=updateConstraint, + update=setConstraintFraming, min=0) smooth_out = bpy.props.IntProperty(name="Out", default=10, description="Amount of frames to smooth out", - update=updateConstraint, + update=setConstraintFraming, min=0) targetMesh = bpy.props.StringProperty(name="Mesh", default="", description="Target of Constraint - Mesh (optional, depends on type)", - update=updateConstraint) + update=setConstraint) active = bpy.props.BoolProperty(name="Active", default=True, description="Constraint is active", - update=updateConstraint) + update=setConstraint) baked = bpy.props.BoolProperty(name="Baked / Applied", default=False, description="Constraint has been baked to NLA layer", @@ -84,18 +84,18 @@ class MocapConstraint(bpy.types.PropertyGroup): targetPoint = bpy.props.FloatVectorProperty(name="Point", size=3, subtype="XYZ", default=(0.0, 0.0, 0.0), description="Target of Constraint - Point", - update=updateConstraint) + update=setConstraint) targetDist = bpy.props.FloatProperty(name="Dist", default=1, description="Distance Constraint - Desired distance", - update=updateConstraint) + update=setConstraint) targetSpace = bpy.props.EnumProperty( items=[("WORLD", "World Space", "Evaluate target in global space"), ("LOCAL", "Object space", "Evaluate target in object space"), ("constrained_boneB", "Other Bone Space", "Evaluate target in specified other bone space")], name="Space", description="In which space should Point type target be evaluated", - update=updateConstraint) + update=setConstraint) type = bpy.props.EnumProperty(name="Type of constraint", items=[("point", "Maintain Position", "Bone is at a specific point"), ("freeze", "Maintain Position at frame", "Bone does not move from location specified in target frame"), @@ -148,7 +148,14 @@ def toggleIKBone(self, context): if not bone.is_in_ik_chain: bone.IKRetarget = False + +class MocapMapping(bpy.types.PropertyGroup): + name = bpy.props.StringProperty() + +bpy.utils.register_class(MocapMapping) + bpy.types.Bone.map = bpy.props.StringProperty() +bpy.types.Bone.reverseMap = bpy.props.CollectionProperty(type=MocapMapping) bpy.types.Bone.foot = bpy.props.BoolProperty(name="Foot", description="Marks this bone as a 'foot', which determines retargeted animation's translation", default=False) @@ -225,6 +232,7 @@ class MocapPanel(bpy.types.Panel): else: row.label(" ") row.label(" ") + self.layout.operator("mocap.savemapping", text='Save mapping') self.layout.operator("mocap.retarget", text='RETARGET!') @@ -283,9 +291,49 @@ class OBJECT_OT_RetargetButton(bpy.types.Operator): bl_label = "Retargets active action from Performer to Enduser" def execute(self, context): - retarget.totalRetarget() + enduser_obj = context.active_object + performer_obj = [obj for obj in context.selected_objects if obj != enduser_obj] + if enduser_obj is None or len(performer_obj) != 1: + print("Need active and selected armatures") + else: + performer_obj = performer_obj[0] + scene = context.scene + s_frame = scene.frame_start + e_frame = scene.frame_end + retarget.totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame) + return {"FINISHED"} + + @classmethod + def poll(cls, context): + if context.active_object: + activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) + performer_obj = [obj for obj in context.selected_objects if obj != context.active_object] + if performer_obj: + return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) + else: + return False + + +class OBJECT_OT_SaveMappingButton(bpy.types.Operator): + bl_idname = "mocap.savemapping" + bl_label = "Saves user generated mapping from Performer to Enduser" + + def execute(self, context): + enduser_obj = bpy.context.active_object + performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj][0] + retarget.createDictionary(performer_obj.data, enduser_obj.data) return {"FINISHED"} + @classmethod + def poll(cls, context): + if context.active_object: + activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) + performer_obj = [obj for obj in context.selected_objects if obj != context.active_object] + if performer_obj: + return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) + else: + return False + class OBJECT_OT_ConvertSamplesButton(bpy.types.Operator): bl_idname = "mocap.samples" @@ -295,6 +343,10 @@ class OBJECT_OT_ConvertSamplesButton(bpy.types.Operator): mocap_tools.fcurves_simplify() return {"FINISHED"} + @classmethod + def poll(cls, context): + return context.active_object.animation_data + class OBJECT_OT_LooperButton(bpy.types.Operator): bl_idname = "mocap.looper" @@ -304,6 +356,10 @@ class OBJECT_OT_LooperButton(bpy.types.Operator): mocap_tools.autoloop_anim() return {"FINISHED"} + @classmethod + def poll(cls, context): + return context.active_object.animation_data + class OBJECT_OT_DenoiseButton(bpy.types.Operator): bl_idname = "mocap.denoise" @@ -313,6 +369,14 @@ class OBJECT_OT_DenoiseButton(bpy.types.Operator): mocap_tools.denoise_median() return {"FINISHED"} + @classmethod + def poll(cls, context): + return context.active_object + + @classmethod + def poll(cls, context): + return context.active_object.animation_data + class OBJECT_OT_LimitDOFButton(bpy.types.Operator): bl_idname = "mocap.limitdof" @@ -321,6 +385,16 @@ class OBJECT_OT_LimitDOFButton(bpy.types.Operator): def execute(self, context): return {"FINISHED"} + @classmethod + def poll(cls, context): + if context.active_object: + activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) + performer_obj = [obj for obj in context.selected_objects if obj != context.active_object] + if performer_obj: + return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) + else: + return False + class OBJECT_OT_RotateFixArmature(bpy.types.Operator): bl_idname = "mocap.rotate_fix" @@ -330,8 +404,10 @@ class OBJECT_OT_RotateFixArmature(bpy.types.Operator): mocap_tools.rotate_fix_armature(context.active_object.data) return {"FINISHED"} - #def poll(self, context): - # return context.active_object.data in bpy.data.armatures + @classmethod + def poll(cls, context): + if context.active_object: + return isinstance(context.active_object.data, bpy.types.Armature) class OBJECT_OT_AddMocapConstraint(bpy.types.Operator): @@ -344,6 +420,11 @@ class OBJECT_OT_AddMocapConstraint(bpy.types.Operator): new_mcon = enduser_arm.mocap_constraints.add() return {"FINISHED"} + @classmethod + def poll(cls, context): + if context.active_object: + return isinstance(context.active_object.data, bpy.types.Armature) + class OBJECT_OT_RemoveMocapConstraint(bpy.types.Operator): bl_idname = "mocap.removeconstraint" @@ -362,6 +443,11 @@ class OBJECT_OT_RemoveMocapConstraint(bpy.types.Operator): m_constraints.remove(self.constraint) return {"FINISHED"} + @classmethod + def poll(cls, context): + if context.active_object: + return isinstance(context.active_object.data, bpy.types.Armature) + def register(): bpy.utils.register_module(__name__) -- cgit v1.2.3 From 1ab2e0d40e25d46aa0d56804d0519307a4bf18a8 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Tue, 12 Jul 2011 07:03:25 +0000 Subject: NLA Drawing Tweak - New icons for "solo" toggles Added some new star icons for the "solo" toggles in NLA editor. Unfortunately they look a tad scruffy alongside some of the other icons, although they should hopefully turn out to be more descriptive (especially when combined with some drawing tweaks I've got in the pipeline...) --- release/datafiles/blenderbuttons | Bin 211658 -> 213035 bytes 1 file changed, 0 insertions(+), 0 deletions(-) (limited to 'release') diff --git a/release/datafiles/blenderbuttons b/release/datafiles/blenderbuttons index 99b464095ed..4a308e7151d 100644 Binary files a/release/datafiles/blenderbuttons and b/release/datafiles/blenderbuttons differ -- cgit v1.2.3 From fa78d3271f538199332984cac8b98386ec17845e Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 13 Jul 2011 12:02:39 +0000 Subject: Bugfix: DopeSheet + Graph Editors were referring to wrong operator for their "Duplicate Keys" menu entry --- release/scripts/startup/bl_ui/space_dopesheet.py | 2 +- release/scripts/startup/bl_ui/space_graph.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 525e87db284..b4f196dab74 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -291,7 +291,7 @@ class DOPESHEET_MT_key(bpy.types.Menu): layout.operator("action.keyframe_insert") layout.separator() - layout.operator("action.duplicate") + layout.operator("action.duplicate_move") layout.operator("action.delete") layout.separator() diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index 1987143f660..31b5168eb92 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -213,7 +213,7 @@ class GRAPH_MT_key(bpy.types.Menu): layout.operator("graph.sound_bake") layout.separator() - layout.operator("graph.duplicate") + layout.operator("graph.duplicate_move") layout.operator("graph.delete") layout.separator() -- cgit v1.2.3 From b3714ec8ed1718979394615cadddbb39bff17951 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Thu, 14 Jul 2011 13:26:23 +0000 Subject: Bugfix: Baking mocap constraints now works for user created IK bones --- release/scripts/modules/mocap_constraints.py | 150 ++++++++++++++++----------- release/scripts/modules/retarget.py | 25 ++++- release/scripts/startup/ui_mocap.py | 68 ++++++++++-- 3 files changed, 167 insertions(+), 76 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py index f4d96d6a5d0..56589403ce2 100644 --- a/release/scripts/modules/mocap_constraints.py +++ b/release/scripts/modules/mocap_constraints.py @@ -40,6 +40,7 @@ def getConsObj(bone): def consObjToBone(cons_obj): + #Utility function - returns related bone from ik object if cons_obj.name[-3:] == "Org": return cons_obj.name[:-3] else: @@ -49,26 +50,31 @@ def consObjToBone(cons_obj): def addNewConstraint(m_constraint, cons_obj): + #Decide the correct Blender constraint according to the Mocap constraint type if m_constraint.type == "point" or m_constraint.type == "freeze": c_type = "LIMIT_LOCATION" if m_constraint.type == "distance": c_type = "LIMIT_DISTANCE" if m_constraint.type == "floor": c_type = "FLOOR" + #create and store the new constraint within m_constraint real_constraint = cons_obj.constraints.new(c_type) real_constraint.name = "Mocap constraint " + str(len(cons_obj.constraints)) m_constraint.real_constraint_bone = consObjToBone(cons_obj) m_constraint.real_constraint = real_constraint.name + #set the rest of the constraint properties setConstraint(m_constraint, bpy.context) def removeConstraint(m_constraint, cons_obj): + #remove the influence fcurve and Blender constraint oldConstraint = cons_obj.constraints[m_constraint.real_constraint] removeInfluenceFcurve(cons_obj, bpy.context.active_object, oldConstraint) cons_obj.constraints.remove(oldConstraint) -### Update functions. There are 2: UpdateType/UpdateBone -### and update for the others. +### Update functions. There are 3: UpdateType/Bone +### update framing (deals with changes in the desired frame range) +### And setConstraint which deals with the rest def updateConstraintBoneType(m_constraint, context): @@ -93,7 +99,9 @@ def setConstraintFraming(m_constraint, context): bone = bones[m_constraint.constrained_bone] cons_obj = getConsObj(bone) real_constraint = cons_obj.constraints[m_constraint.real_constraint] + #remove the old keyframes removeInfluenceFcurve(cons_obj, obj, real_constraint) + #set the new ones according to the m_constraint properties s, e = m_constraint.s_frame, m_constraint.e_frame s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out real_constraint.influence = 1 @@ -105,12 +113,14 @@ def setConstraintFraming(m_constraint, context): def removeInfluenceFcurve(cons_obj, obj, real_constraint): + #Determine if the constrained object is a bone or an empty if isinstance(cons_obj, bpy.types.PoseBone): fcurves = obj.animation_data.action.fcurves else: fcurves = cons_obj.animation_data.action.fcurves - + #Find the RNA data path of the constraint's influence influence_RNA = real_constraint.path_from_id("influence") + #Retrieve the correct fcurve via the RNA data path and remove it fcurve = [fcurve for fcurve in fcurves if fcurve.data_path == influence_RNA] #clear the fcurve and set the frames. if fcurve: @@ -131,7 +141,7 @@ def setConstraint(m_constraint, context): real_constraint = cons_obj.constraints[m_constraint.real_constraint] #frame changing section - #setConstraintFraming(m_constraint, cons_obj, obj, real_constraint) + setConstraintFraming(m_constraint, context) #Set the blender constraint parameters if m_constraint.type == "point": @@ -154,7 +164,7 @@ def setConstraint(m_constraint, context): real_constraint.owner_space = m_constraint.targetSpace bpy.context.scene.frame_set(m_constraint.s_frame) if isinstance(cons_obj, bpy.types.PoseBone): - x, y, z = cons_obj.center + (cons_obj.vector / 2) + x, y, z = cons_obj.bone.center + (cons_obj.bone.vector / 2) + obj.matrix_world.to_translation() else: x, y, z = cons_obj.matrix_world.to_translation() @@ -178,82 +188,100 @@ def setConstraint(m_constraint, context): real_constraint.distance = m_constraint.targetDist # active/baked check - real_constraint.mute = (not m_constraint.active) and (m_constraint.baked) - + real_constraint.mute = (not m_constraint.active) -def updateBake(self, context): - if self.baked: - print("baking...") - bakeConstraint(self, context) - else: - print("unbaking...") - unbakeConstraint(self, context) - -def bakeTransformFK(anim_data, s_frame, e_frame, end_bone, bones, cons_obj): - mute_ik = False +def locBake(s_frame, e_frame, bones): + scene = bpy.context.scene + bakeDict = {} + for bone in bones: + bakeDict[bone.name] = {} + for t in range(s_frame, e_frame): + scene.frame_set(t) + for bone in bones: + bakeDict[bone.name][t] = bone.matrix.copy() + for t in range(s_frame, e_frame): + for bone in bones: + print(bone.bone.matrix_local.to_translation()) + bone.matrix = bakeDict[bone.name][t] + bone.keyframe_insert("location", frame=t) + + +# Baking function which bakes all bones effected by the constraint +def bakeAllConstraints(obj, s_frame, e_frame, bones): for bone in bones: bone.bone.select = False - ik = hasIKConstraint(end_bone) - if not isinstance(cons_obj, bpy.types.PoseBone) and ik: - if ik.chain_count == 0: - selectedBones = bones + selectedBones = [] # Marks bones that need a full bake + simpleBake = [] # Marks bones that need only a location bake + for end_bone in bones: + if end_bone.name in [m_constraint.real_constraint_bone for m_constraint in obj.data.mocap_constraints]: + #For all bones that have a constraint: + ik = hasIKConstraint(end_bone) + cons_obj = getConsObj(end_bone) + if ik: + #If it's an auto generated IK: + if ik.chain_count == 0: + selectedBones += bones # Chain len 0, bake everything + else: + selectedBones += [end_bone] + end_bone.parent_recursive[:ik.chain_count - 1] # Bake the chain else: - selectedBones = [end_bone] + end_bone.parent_recursive[:ik.chain_count - 1] - mute_ik = True - else: - selectedBones = [end_bone] - print(selectedBones) + #It's either an FK bone which we should just bake + #OR a user created IK target bone + simpleBake += [end_bone] for bone in selectedBones: bone.bone.select = True - anim_data.action = nla.bake(s_frame, - e_frame, action=anim_data.action) - return mute_ik - - -def bakeConstraint(m_constraint, context): - obj = context.active_object - bones = obj.pose.bones - end_bone = bones[m_constraint.constrained_bone] - cons_obj = getConsObj(end_bone) - s, e = m_constraint.s_frame, m_constraint.e_frame - s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out - s_frame = s - s_in - e_frame = e + s_out - mute_ik = bakeTransformFK(obj.animation_data, s_frame, e_frame, end_bone, bones, cons_obj) - if mute_ik: - ik_con = hasIKConstraint(end_bone) - ik_con.mute = True - real_constraint = cons_obj.constraints[m_constraint.real_constraint] - real_constraint.mute = True constraintTrack = obj.animation_data.nla_tracks["Mocap constraints"] constraintStrip = constraintTrack.strips[0] constraintStrip.action_frame_start = s_frame constraintStrip.action_frame_end = e_frame constraintStrip.frame_start = s_frame constraintStrip.frame_end = e_frame + if selectedBones: + #Use bake function from NLA Bake Action operator + nla.bake(s_frame, e_frame, action=constraintStrip.action, only_selected=True, do_pose=True, do_object=False) + if simpleBake: + #Do a "simple" bake, location only, world space only. + locBake(s_frame, e_frame, simpleBake) -def unbakeConstraint(m_constraint, context): - # to unbake a constraint we need to delete the whole strip - # and rebake all the other constraints +#Calls the baking function and decativates releveant constraints +def bakeConstraints(context): + obj = context.active_object + bones = obj.pose.bones + s_frame, e_frame = context.scene.frame_start, context.scene.frame_end + #Bake relevant bones + bakeAllConstraints(obj, s_frame, e_frame, bones) + for m_constraint in obj.data.mocap_constraints: + end_bone = bones[m_constraint.real_constraint_bone] + cons_obj = getConsObj(end_bone) + # It's a control empty: turn the ik off + if not isinstance(cons_obj, bpy.types.PoseBone): + ik_con = hasIKConstraint(end_bone) + if ik_con: + ik_con.mute = True + # Deactivate related Blender Constraint + m_constraint.active = False + + +#Deletes the baked fcurves and reactivates relevant constraints +def unbakeConstraints(context): + # to unbake constraints we delete the whole strip obj = context.active_object bones = obj.pose.bones - end_bone = bones[m_constraint.constrained_bone] - cons_obj = getConsObj(end_bone) scene = bpy.context.scene constraintTrack = obj.animation_data.nla_tracks["Mocap constraints"] constraintStrip = constraintTrack.strips[0] action = constraintStrip.action + # delete the fcurves on the strip for fcurve in action.fcurves: action.fcurves.remove(fcurve) - for other_m_constraint in obj.data.mocap_constraints: - if m_constraint != other_m_constraint: - bakeConstraint(other_m_constraint) - # It's a control empty: turn the ik back on - if not isinstance(cons_obj, bpy.types.PoseBone): - ik_con = hasIKConstraint(end_bone) - if ik_con: - ik_con.mute = False - real_constraint = cons_obj.constraints[m_constraint.real_constraint] - real_constraint.mute = False + # reactivate relevant constraints + for m_constraint in obj.data.mocap_constraints: + end_bone = bones[m_constraint.real_constraint_bone] + cons_obj = getConsObj(end_bone) + # It's a control empty: turn the ik back on + if not isinstance(cons_obj, bpy.types.PoseBone): + ik_con = hasIKConstraint(end_bone) + if ik_con: + ik_con.mute = False + m_constraint.active = True diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index ef1bc7a1488..f8d424fbb5a 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -49,10 +49,15 @@ def createDictionary(perf_arm, end_arm): root = end_arm.bones[0].name feetBones = [bone.name for bone in perf_arm.bones if bone.foot] return feetBones, root -# list of empties created to keep track of "original" -# position data -# in final product, these locations can be stored as custom props -# these help with constraining, etc. + + +def loadMapping(perf_arm, end_arm): + + for end_bone in end_arm.bones: + #find its match and add perf_bone to the match's mapping + if end_bone.reverseMap: + for perf_bone in end_bone.reverseMap: + perf_arm.bones[perf_bone.name].map = end_bone.name #creation of intermediate armature # the intermediate armature has the hiearchy of the end user, @@ -248,11 +253,13 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame stride_bone.name = "stride_bone" if linearAvg: + #determine the average change in scale needed avg = sum(linearAvg) / len(linearAvg) scene.frame_set(s_frame) initialPos = (tailLoc(perf_bones[perfRoot]) / avg) for t in range(s_frame, e_frame): scene.frame_set(t) + #calculate the new position, by dividing by the found ratio between performer and enduser newTranslation = (tailLoc(perf_bones[perfRoot]) / avg) stride_bone.location = (newTranslation - initialPos) * enduser_obj_mat stride_bone.keyframe_insert("location") @@ -281,6 +288,7 @@ def IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene): else: target = ik_constraint.target + # bake the correct locations for the ik target bones for t in range(s_frame, e_frame): scene.frame_set(t) if target_is_bone: @@ -308,15 +316,17 @@ def turnOffIK(enduser_obj): ik_constraint.mute = True +#copy the object matrixes and clear them (to be reinserted later) def cleanAndStoreObjMat(performer_obj, enduser_obj): perf_obj_mat = performer_obj.matrix_world.copy() enduser_obj_mat = enduser_obj.matrix_world.copy() - zero_mat = Matrix() # Matrix(((0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0))) + zero_mat = Matrix() performer_obj.matrix_world = zero_mat enduser_obj.matrix_world = zero_mat return perf_obj_mat, enduser_obj_mat +#restore the object matrixes after parenting the auto generated IK empties def restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone): pose_bones = enduser_obj.pose.bones for pose_bone in pose_bones: @@ -328,6 +338,7 @@ def restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, str enduser_obj.parent = stride_bone +#create (or return if exists) the related IK empty to the bone def originalLocationTarget(end_bone): if not end_bone.name + "Org" in bpy.data.objects: bpy.ops.object.add() @@ -339,6 +350,7 @@ def originalLocationTarget(end_bone): return empty +#create the specified NLA setup for base animation, constraints and tweak layer. def NLASystemInitialize(enduser_obj, s_frame): anim_data = enduser_obj.animation_data mocapAction = anim_data.action @@ -351,10 +363,13 @@ def NLASystemInitialize(enduser_obj, s_frame): constraintTrack.name = "Mocap constraints" constraintAction = bpy.data.actions.new("Mocap constraints") constraintStrip = constraintTrack.strips.new("Mocap constraints", s_frame, constraintAction) + constraintStrip.extrapolation = "NOTHING" anim_data.nla_tracks.active = constraintTrack anim_data.action = constraintAction + anim_data.action_extrapolation = "NOTHING" +#Main function that runs the retargeting sequence. def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): perf_arm = performer_obj.data end_arm = enduser_obj.data diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index b09f9705a56..9a36f076ece 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -54,20 +54,20 @@ class MocapConstraint(bpy.types.PropertyGroup): s_frame = bpy.props.IntProperty(name="S", default=1, description="Start frame of constraint", - update=setConstraintFraming) + update=setConstraint) e_frame = bpy.props.IntProperty(name="E", default=500, description="End frame of constrain", - update=setConstraintFraming) + update=setConstraint) smooth_in = bpy.props.IntProperty(name="In", default=10, description="Amount of frames to smooth in", - update=setConstraintFraming, + update=setConstraint, min=0) smooth_out = bpy.props.IntProperty(name="Out", default=10, description="Amount of frames to smooth out", - update=setConstraintFraming, + update=setConstraint, min=0) targetMesh = bpy.props.StringProperty(name="Mesh", default="", @@ -77,10 +77,6 @@ class MocapConstraint(bpy.types.PropertyGroup): default=True, description="Constraint is active", update=setConstraint) - baked = bpy.props.BoolProperty(name="Baked / Applied", - default=False, - description="Constraint has been baked to NLA layer", - update=updateBake) targetPoint = bpy.props.FloatVectorProperty(name="Point", size=3, subtype="XYZ", default=(0.0, 0.0, 0.0), description="Target of Constraint - Point", @@ -232,7 +228,9 @@ class MocapPanel(bpy.types.Panel): else: row.label(" ") row.label(" ") - self.layout.operator("mocap.savemapping", text='Save mapping') + mapRow = self.layout.row() + mapRow.operator("mocap.savemapping", text='Save mapping') + mapRow.operator("mocap.loadmapping", text='Load mapping') self.layout.operator("mocap.retarget", text='RETARGET!') @@ -251,6 +249,8 @@ class MocapConstraintsPanel(bpy.types.Panel): enduser_obj = context.active_object enduser_arm = enduser_obj.data layout.operator("mocap.addconstraint") + layout.operator("mocap.bakeconstraints") + layout.operator("mocap.unbakeconstraints") layout.separator() for i, m_constraint in enumerate(enduser_arm.mocap_constraints): box = layout.box() @@ -281,7 +281,6 @@ class MocapConstraintsPanel(bpy.types.Panel): targetPropCol.prop(m_constraint, 'targetDist') checkRow = box.row() checkRow.prop(m_constraint, 'active') - checkRow.prop(m_constraint, 'baked') layout.operator("mocap.removeconstraint", text="Remove constraint").constraint = i layout.separator() @@ -335,6 +334,27 @@ class OBJECT_OT_SaveMappingButton(bpy.types.Operator): return False +class OBJECT_OT_LoadMappingButton(bpy.types.Operator): + bl_idname = "mocap.loadmapping" + bl_label = "Loads user generated mapping from Performer to Enduser" + + def execute(self, context): + enduser_obj = bpy.context.active_object + performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj][0] + retarget.loadMapping(performer_obj.data, enduser_obj.data) + return {"FINISHED"} + + @classmethod + def poll(cls, context): + if context.active_object: + activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) + performer_obj = [obj for obj in context.selected_objects if obj != context.active_object] + if performer_obj: + return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) + else: + return False + + class OBJECT_OT_ConvertSamplesButton(bpy.types.Operator): bl_idname = "mocap.samples" bl_label = "Converts samples / simplifies keyframes to beziers" @@ -449,6 +469,34 @@ class OBJECT_OT_RemoveMocapConstraint(bpy.types.Operator): return isinstance(context.active_object.data, bpy.types.Armature) +class OBJECT_OT_BakeMocapConstraints(bpy.types.Operator): + bl_idname = "mocap.bakeconstraints" + bl_label = "Bake all constraints to target armature" + + def execute(self, context): + bakeConstraints(context) + return {"FINISHED"} + + @classmethod + def poll(cls, context): + if context.active_object: + return isinstance(context.active_object.data, bpy.types.Armature) + + +class OBJECT_OT_UnbakeMocapConstraints(bpy.types.Operator): + bl_idname = "mocap.unbakeconstraints" + bl_label = "Unbake all constraints to target armature" + + def execute(self, context): + unbakeConstraints(context) + return {"FINISHED"} + + @classmethod + def poll(cls, context): + if context.active_object: + return isinstance(context.active_object.data, bpy.types.Armature) + + def register(): bpy.utils.register_module(__name__) -- cgit v1.2.3 From 04e028a0c5d9ffe2edc3a42a90e9314dbd9e95c5 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Fri, 15 Jul 2011 10:07:02 +0000 Subject: Bugfix: Retargeting now works when user rig bones are not connected to their parents. --- release/scripts/modules/retarget.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index f8d424fbb5a..0b694453865 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -117,6 +117,14 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene inter_obj.name = "intermediate" bpy.context.scene.objects.active = inter_obj bpy.ops.object.mode_set(mode='EDIT') + #add some temporary connecting bones in case end user bones are not connected to their parents + for bone in inter_obj.data.edit_bones: + if not bone.use_connect and bone.parent: + newBone = inter_obj.data.edit_bones.new("Temp") + newBone.head = bone.parent.head + newBone.tail = bone.head + newBone.parent = bone.parent + bone.parent = newBone #resets roll bpy.ops.armature.calculate_roll(type='Z') bpy.ops.object.mode_set(mode="OBJECT") @@ -156,7 +164,10 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene): rest_matrix = trg_bone.bone.matrix_local if trg_bone.parent and trg_bone.bone.use_inherit_rotation: - parent_mat = src_bone.parent.matrix + srcParent = src_bone.parent + if not trg_bone.bone.use_connect: + srcParent = srcParent.parent + parent_mat = srcParent.matrix parent_rest = trg_bone.parent.bone.matrix_local parent_rest_inv = parent_rest.copy() parent_rest_inv.invert() @@ -168,7 +179,7 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene): rest_matrix_inv = rest_matrix.copy() rest_matrix_inv.invert() bake_matrix = rest_matrix_inv * bake_matrix - trg_bone.matrix_basis = bake_matrix + end_bone.matrix_basis = bake_matrix rot_mode = end_bone.rotation_mode if rot_mode == "QUATERNION": end_bone.keyframe_insert("rotation_quaternion") -- cgit v1.2.3 From 351a60387409eee7fe468905b7003493a46bc8c8 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Sat, 16 Jul 2011 13:36:47 +0000 Subject: Keyframing Motion capture properties now works for the Point constraint. Also, Floor constraint has been implemented, using Object's raycasting function in Python --- release/scripts/modules/mocap_constraints.py | 146 +++++++++++++++++++++++---- release/scripts/startup/ui_mocap.py | 8 +- 2 files changed, 130 insertions(+), 24 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py index 56589403ce2..0fd39b5785f 100644 --- a/release/scripts/modules/mocap_constraints.py +++ b/release/scripts/modules/mocap_constraints.py @@ -56,7 +56,7 @@ def addNewConstraint(m_constraint, cons_obj): if m_constraint.type == "distance": c_type = "LIMIT_DISTANCE" if m_constraint.type == "floor": - c_type = "FLOOR" + c_type = "LIMIT_LOCATION" #create and store the new constraint within m_constraint real_constraint = cons_obj.constraints.new(c_type) real_constraint.name = "Mocap constraint " + str(len(cons_obj.constraints)) @@ -69,7 +69,7 @@ def addNewConstraint(m_constraint, cons_obj): def removeConstraint(m_constraint, cons_obj): #remove the influence fcurve and Blender constraint oldConstraint = cons_obj.constraints[m_constraint.real_constraint] - removeInfluenceFcurve(cons_obj, bpy.context.active_object, oldConstraint) + removeFcurves(cons_obj, bpy.context.active_object, oldConstraint, m_constraint) cons_obj.constraints.remove(oldConstraint) ### Update functions. There are 3: UpdateType/Bone @@ -112,19 +112,66 @@ def setConstraintFraming(m_constraint, context): real_constraint.keyframe_insert(data_path="influence", frame=e + s_out) -def removeInfluenceFcurve(cons_obj, obj, real_constraint): +def removeFcurves(cons_obj, obj, real_constraint, m_constraint): #Determine if the constrained object is a bone or an empty if isinstance(cons_obj, bpy.types.PoseBone): fcurves = obj.animation_data.action.fcurves else: fcurves = cons_obj.animation_data.action.fcurves #Find the RNA data path of the constraint's influence - influence_RNA = real_constraint.path_from_id("influence") + RNA_paths = [] + RNA_paths.append(real_constraint.path_from_id("influence")) + if m_constraint.type == "floor" or m_constraint.type == "point": + RNA_paths += [real_constraint.path_from_id("max_x"), real_constraint.path_from_id("min_x")] + RNA_paths += [real_constraint.path_from_id("max_y"), real_constraint.path_from_id("min_y")] + RNA_paths += [real_constraint.path_from_id("max_z"), real_constraint.path_from_id("min_z")] #Retrieve the correct fcurve via the RNA data path and remove it - fcurve = [fcurve for fcurve in fcurves if fcurve.data_path == influence_RNA] + fcurves_del = [fcurve for fcurve in fcurves if fcurve.data_path in RNA_paths] #clear the fcurve and set the frames. - if fcurve: - fcurves.remove(fcurve[0]) + if fcurves_del: + for fcurve in fcurves_del: + fcurves.remove(fcurve) + #remove armature fcurves (if user keyframed m_constraint properties) + if obj.data.animation_data and m_constraint.type == "point": + if obj.data.animation_data.action: + path = m_constraint.path_from_id("targetPoint") + m_fcurves = [fcurve for fcurve in obj.data.animation_data.action.fcurves if fcurve.data_path == path] + for curve in m_fcurves: + obj.data.animation_data.action.fcurves.remove(curve) + +#Utility function for copying property fcurves over + + +def copyFCurve(newCurve, oldCurve): + for point in oldCurve.keyframe_points: + newCurve.keyframe_points.insert(frame=point.co.x, value=point.co.y) + +#Creates new fcurves for the constraint properties (for floor and point) + + +def createConstraintFCurves(cons_obj, obj, real_constraint): + if isinstance(cons_obj, bpy.types.PoseBone): + c_fcurves = obj.animation_data.action.fcurves + else: + c_fcurves = cons_obj.animation_data.action.fcurves + c_x_path = [real_constraint.path_from_id("max_x"), real_constraint.path_from_id("min_x")] + c_y_path = [real_constraint.path_from_id("max_y"), real_constraint.path_from_id("min_y")] + c_z_path = [real_constraint.path_from_id("max_z"), real_constraint.path_from_id("min_z")] + c_constraints_path = c_x_path + c_y_path + c_z_path + existing_curves = [fcurve for fcurve in c_fcurves if fcurve.data_path in c_constraints_path] + if existing_curves: + for curve in existing_curves: + c_fcurves.remove(curve) + xCurves, yCurves, zCurves = [], [], [] + for path in c_constraints_path: + newCurve = c_fcurves.new(path) + if path in c_x_path: + xCurves.append(newCurve) + elif path in c_y_path: + yCurves.append(newCurve) + else: + zCurves.append(newCurve) + return xCurves, yCurves, zCurves # Function that copies all settings from m_constraint to the real Blender constraints @@ -145,20 +192,35 @@ def setConstraint(m_constraint, context): #Set the blender constraint parameters if m_constraint.type == "point": + constraint_settings = False real_constraint.owner_space = m_constraint.targetSpace - x, y, z = m_constraint.targetPoint - real_constraint.max_x = x - real_constraint.max_y = y - real_constraint.max_z = z - real_constraint.min_x = x - real_constraint.min_y = y - real_constraint.min_z = z - real_constraint.use_max_x = True - real_constraint.use_max_y = True - real_constraint.use_max_z = True - real_constraint.use_min_x = True - real_constraint.use_min_y = True - real_constraint.use_min_z = True + if obj.data.animation_data: + if obj.data.animation_data.action: + path = m_constraint.path_from_id("targetPoint") + m_fcurves = [fcurve for fcurve in obj.data.animation_data.action.fcurves if fcurve.data_path == path] + if m_fcurves: + constraint_settings = True + xCurves, yCurves, zCurves = createConstraintFCurves(cons_obj, obj, real_constraint) + for curve in xCurves: + copyFCurve(curve, m_fcurves[0]) + for curve in yCurves: + copyFCurve(curve, m_fcurves[1]) + for curve in zCurves: + copyFCurve(curve, m_fcurves[2]) + if not constraint_settings: + x, y, z = m_constraint.targetPoint + real_constraint.max_x = x + real_constraint.max_y = y + real_constraint.max_z = z + real_constraint.min_x = x + real_constraint.min_y = y + real_constraint.min_z = z + real_constraint.use_max_x = True + real_constraint.use_max_y = True + real_constraint.use_max_z = True + real_constraint.use_min_x = True + real_constraint.use_min_y = True + real_constraint.use_min_z = True if m_constraint.type == "freeze": real_constraint.owner_space = m_constraint.targetSpace @@ -187,6 +249,50 @@ def setConstraint(m_constraint, context): real_constraint.limit_mode = "LIMITDIST_ONSURFACE" real_constraint.distance = m_constraint.targetDist + if m_constraint.type == "floor" and m_constraint.targetMesh: + real_constraint.mute = True + real_constraint.owner_space = "WORLD" + #calculate the positions thoughout the range + s, e = m_constraint.s_frame, m_constraint.e_frame + s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out + s -= s_in + e += s_out + bakedPos = {} + floor = bpy.data.objects[m_constraint.targetMesh] + c_frame = context.scene.frame_current + for t in range(s, e): + context.scene.frame_set(t) + axis = Vector((0, 0, 100)) * obj.matrix_world.to_3x3() + offset = Vector((0, 0, m_constraint.targetDist)) * obj.matrix_world.to_3x3() + ray_origin = cons_obj.matrix_world.to_translation() - offset # world position of constrained bone + ray_target = ray_origin + axis + #convert ray points to floor's object space + ray_origin *= floor.matrix_world.inverted() + ray_target *= floor.matrix_world.inverted() + hit, nor, ind = floor.ray_cast(ray_origin, ray_target) + if hit != Vector((0, 0, 0)): + bakedPos[t] = (hit * floor.matrix_world) + bakedPos[t] += Vector((0, 0, m_constraint.targetDist)) + else: + bakedPos[t] = cons_obj.matrix_world.to_translation() + context.scene.frame_set(c_frame) + #create keyframes for real constraint + xCurves, yCurves, zCurves = createConstraintFCurves(cons_obj, obj, real_constraint) + for frame in bakedPos.keys(): + pos = bakedPos[frame] + for xCurve in xCurves: + xCurve.keyframe_points.insert(frame=frame, value=pos.x) + for yCurve in yCurves: + yCurve.keyframe_points.insert(frame=frame, value=pos.y) + for zCurve in zCurves: + zCurve.keyframe_points.insert(frame=frame, value=pos.z) + real_constraint.use_max_x = True + real_constraint.use_max_y = True + real_constraint.use_max_z = True + real_constraint.use_min_x = True + real_constraint.use_min_y = True + real_constraint.use_min_z = True + # active/baked check real_constraint.mute = (not m_constraint.active) diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 9a36f076ece..356de00e8ee 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -81,9 +81,9 @@ class MocapConstraint(bpy.types.PropertyGroup): subtype="XYZ", default=(0.0, 0.0, 0.0), description="Target of Constraint - Point", update=setConstraint) - targetDist = bpy.props.FloatProperty(name="Dist", - default=1, - description="Distance Constraint - Desired distance", + targetDist = bpy.props.FloatProperty(name="Offset", + default=0.0, + description="Distance and Floor Constraints - Desired offset", update=setConstraint) targetSpace = bpy.props.EnumProperty( items=[("WORLD", "World Space", "Evaluate target in global space"), @@ -277,7 +277,7 @@ class MocapConstraintsPanel(bpy.types.Panel): box.prop(m_constraint, 'targetSpace') if m_constraint.type == "point": targetPropCol.prop(m_constraint, 'targetPoint') - if m_constraint.type == "distance": + if m_constraint.type == "distance" or m_constraint.type == "floor": targetPropCol.prop(m_constraint, 'targetDist') checkRow = box.row() checkRow.prop(m_constraint, 'active') -- cgit v1.2.3 From 19aaadcbaba2aff7b4a8d6d55621e1acc061616e Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Sat, 16 Jul 2011 13:48:43 +0000 Subject: Small bugfix for prior commit - Removing constraints no longer causes an error --- release/scripts/modules/mocap_constraints.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py index 0fd39b5785f..7a49a96b7b1 100644 --- a/release/scripts/modules/mocap_constraints.py +++ b/release/scripts/modules/mocap_constraints.py @@ -100,7 +100,7 @@ def setConstraintFraming(m_constraint, context): cons_obj = getConsObj(bone) real_constraint = cons_obj.constraints[m_constraint.real_constraint] #remove the old keyframes - removeInfluenceFcurve(cons_obj, obj, real_constraint) + removeFcurves(cons_obj, obj, real_constraint, m_constraint) #set the new ones according to the m_constraint properties s, e = m_constraint.s_frame, m_constraint.e_frame s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out -- cgit v1.2.3 From 0dcc7d05abe9d1557675c63e07f8b5ff3cb49ec3 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Mon, 18 Jul 2011 18:44:54 +0000 Subject: Bugfixing for retargeting - unconnected bones now retarget alot better. Also some placeholder code for a fix scale operator --- release/scripts/modules/mocap_tools.py | 10 ++++++++++ release/scripts/modules/retarget.py | 23 +++++++++++++++++++---- release/scripts/startup/ui_mocap.py | 22 ++++++++++++++++++++++ 3 files changed, 51 insertions(+), 4 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index 33e9105201c..1ce76dfbe6f 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -567,3 +567,13 @@ def rotate_fix_armature(arm_data): for bone in connectedBones: arm_data.edit_bones[bone].use_connect = True bpy.ops.object.mode_set(mode='OBJECT', toggle=False) + + +def scale_fix_armature(performer_obj, enduser_obj): + perf_bones = performer_obj.data.bones + end_bones = enduser_obj.data.bones + + #perf_avg = performer_obj.dimensions + #end_avg = enduser_obj.dimensions + #print(perf_avg, end_avg) + #performer_obj.scale /= (perf_avg / end_avg) diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 0b694453865..e8c9f3e25aa 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -105,7 +105,12 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene else: perf_bone = performer_bones[perf_bone_name[0].name] inter_bone.matrix_basis = singleBoneRetarget(inter_bone, perf_bone) - + elif inter_bone.parent: + if "Temp" in inter_bone.parent.name: + inter_bone.parent.bone.use_inherit_rotation = True + inter_bone.bone.use_inherit_rotation = True + else: + inter_bone.bone.use_inherit_rotation = True inter_bone.keyframe_insert("rotation_quaternion") for child in inter_bone.children: retargetPerfToInter(child) @@ -119,12 +124,14 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene bpy.ops.object.mode_set(mode='EDIT') #add some temporary connecting bones in case end user bones are not connected to their parents for bone in inter_obj.data.edit_bones: - if not bone.use_connect and bone.parent: + if not bone.use_connect and bone.parent and inter_obj.data.bones[bone.name].reverseMap: newBone = inter_obj.data.edit_bones.new("Temp") - newBone.head = bone.parent.head + newBone.head = bone.parent.tail newBone.tail = bone.head newBone.parent = bone.parent bone.parent = newBone + bone.use_connect = True + newBone.use_connect = True #resets roll bpy.ops.armature.calculate_roll(type='Z') bpy.ops.object.mode_set(mode="OBJECT") @@ -165,7 +172,7 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene): if trg_bone.parent and trg_bone.bone.use_inherit_rotation: srcParent = src_bone.parent - if not trg_bone.bone.use_connect: + if "Temp" in srcParent.name: srcParent = srcParent.parent parent_mat = srcParent.matrix parent_rest = trg_bone.parent.bone.matrix_local @@ -187,6 +194,8 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene): end_bone.keyframe_insert("rotation_axis_angle") else: end_bone.keyframe_insert("rotation_euler") + if not end_bone.bone.use_connect: + end_bone.keyframe_insert("location") for bone in end_bone.children: bakeTransform(bone) @@ -384,11 +393,16 @@ def NLASystemInitialize(enduser_obj, s_frame): def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): perf_arm = performer_obj.data end_arm = enduser_obj.data + print("creating Dictionary") feetBones, root = createDictionary(perf_arm, end_arm) + print("cleaning stuff up") perf_obj_mat, enduser_obj_mat = cleanAndStoreObjMat(performer_obj, enduser_obj) turnOffIK(enduser_obj) + print("creating intermediate armature") inter_obj = createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene) + print("retargeting from intermediate to end user") retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene) + print("retargeting root translation and clean up") stride_bone = copyTranslation(performer_obj, enduser_obj, feetBones, root, s_frame, e_frame, scene, enduser_obj_mat) IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene) restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone) @@ -396,6 +410,7 @@ def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): bpy.ops.object.select_name(name=inter_obj.name, extend=False) bpy.ops.object.delete() NLASystemInitialize(enduser_obj, s_frame) + print("retargeting done!") if __name__ == "__main__": diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 356de00e8ee..0e623f44d9a 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -191,6 +191,7 @@ class MocapPanel(bpy.types.Panel): row.operator("mocap.samples", text='Samples to Beziers') row.operator("mocap.denoise", text='Clean noise') row.operator("mocap.rotate_fix", text='Fix BVH Axis Orientation') + row.operator("mocap.scale_fix", text='Auto scale Performer') row2 = self.layout.row(align=True) row2.operator("mocap.looper", text='Loop animation') row2.operator("mocap.limitdof", text='Constrain Rig') @@ -430,6 +431,27 @@ class OBJECT_OT_RotateFixArmature(bpy.types.Operator): return isinstance(context.active_object.data, bpy.types.Armature) +class OBJECT_OT_ScaleFixArmature(bpy.types.Operator): + bl_idname = "mocap.scale_fix" + bl_label = "Scales performer armature to match target armature" + + def execute(self, context): + enduser_obj = bpy.context.active_object + performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj][0] + mocap_tools.scale_fix_armature(performer_obj, enduser_obj) + return {"FINISHED"} + + @classmethod + def poll(cls, context): + if context.active_object: + activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) + performer_obj = [obj for obj in context.selected_objects if obj != context.active_object] + if performer_obj: + return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) + else: + return False + + class OBJECT_OT_AddMocapConstraint(bpy.types.Operator): bl_idname = "mocap.addconstraint" bl_label = "Add constraint to target armature" -- cgit v1.2.3 From 7c4aed7fa608ea38eb9e885e25cf80f72ca07703 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Mon, 18 Jul 2011 19:33:11 +0000 Subject: Even more bugfixes for retarget, for various types of special cases. --- release/scripts/modules/retarget.py | 38 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 20 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index e8c9f3e25aa..0602de5e596 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -105,15 +105,7 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene else: perf_bone = performer_bones[perf_bone_name[0].name] inter_bone.matrix_basis = singleBoneRetarget(inter_bone, perf_bone) - elif inter_bone.parent: - if "Temp" in inter_bone.parent.name: - inter_bone.parent.bone.use_inherit_rotation = True - inter_bone.bone.use_inherit_rotation = True - else: - inter_bone.bone.use_inherit_rotation = True inter_bone.keyframe_insert("rotation_quaternion") - for child in inter_bone.children: - retargetPerfToInter(child) #creates the intermediate armature object inter_obj = enduser_obj.copy() @@ -123,16 +115,19 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene bpy.context.scene.objects.active = inter_obj bpy.ops.object.mode_set(mode='EDIT') #add some temporary connecting bones in case end user bones are not connected to their parents + print("creating temp bones") for bone in inter_obj.data.edit_bones: - if not bone.use_connect and bone.parent and inter_obj.data.bones[bone.name].reverseMap: - newBone = inter_obj.data.edit_bones.new("Temp") - newBone.head = bone.parent.tail - newBone.tail = bone.head - newBone.parent = bone.parent - bone.parent = newBone - bone.use_connect = True - newBone.use_connect = True + if not bone.use_connect and bone.parent: + if inter_obj.data.bones[bone.parent.name].reverseMap or inter_obj.data.bones[bone.name].reverseMap: + newBone = inter_obj.data.edit_bones.new("Temp") + newBone.head = bone.parent.tail + newBone.tail = bone.head + newBone.parent = bone.parent + bone.parent = newBone + bone.use_connect = True + newBone.use_connect = True #resets roll + print("retargeting to intermediate") bpy.ops.armature.calculate_roll(type='Z') bpy.ops.object.mode_set(mode="OBJECT") inter_obj.data.name = "inter_arm" @@ -141,12 +136,15 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene inter_bones = inter_obj.pose.bones #clears inheritance for inter_bone in inter_bones: - inter_bone.bone.use_inherit_rotation = False + if inter_bone.bone.reverseMap: + inter_bone.bone.use_inherit_rotation = False + else: + inter_bone.bone.use_inherit_rotation = True for t in range(s_frame, e_frame): scene.frame_set(t) - inter_bone = inter_bones[root] - retargetPerfToInter(inter_bone) + for bone in inter_bones: + retargetPerfToInter(bone) return inter_obj @@ -217,7 +215,7 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame perf_bones = performer_obj.pose.bones end_bones = enduser_obj.pose.bones - perfRoot = end_bones[root].bone.reverseMap[0].name + perfRoot = perf_bones[0].name endFeet = [perf_bones[perfBone].bone.map for perfBone in perfFeet] locDictKeys = perfFeet + endFeet + [perfRoot] -- cgit v1.2.3 From 365ac2f9e34a7421fa3a5ebe9a941d7d23f43208 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Tue, 19 Jul 2011 16:33:28 +0000 Subject: Added tooltips to all operators in the Mocap panels --- release/scripts/startup/ui_mocap.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'release') diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 0e623f44d9a..fe5ae72f280 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -287,6 +287,7 @@ class MocapConstraintsPanel(bpy.types.Panel): class OBJECT_OT_RetargetButton(bpy.types.Operator): + '''Retarget animation from selected armature to active armature ''' bl_idname = "mocap.retarget" bl_label = "Retargets active action from Performer to Enduser" @@ -315,6 +316,7 @@ class OBJECT_OT_RetargetButton(bpy.types.Operator): class OBJECT_OT_SaveMappingButton(bpy.types.Operator): + '''Save mapping to active armature (for future retargets) ''' bl_idname = "mocap.savemapping" bl_label = "Saves user generated mapping from Performer to Enduser" @@ -336,6 +338,7 @@ class OBJECT_OT_SaveMappingButton(bpy.types.Operator): class OBJECT_OT_LoadMappingButton(bpy.types.Operator): + '''Load saved mapping from active armature''' bl_idname = "mocap.loadmapping" bl_label = "Loads user generated mapping from Performer to Enduser" @@ -357,6 +360,7 @@ class OBJECT_OT_LoadMappingButton(bpy.types.Operator): class OBJECT_OT_ConvertSamplesButton(bpy.types.Operator): + '''Convert active armature's sampled keyframed to beziers''' bl_idname = "mocap.samples" bl_label = "Converts samples / simplifies keyframes to beziers" @@ -370,6 +374,7 @@ class OBJECT_OT_ConvertSamplesButton(bpy.types.Operator): class OBJECT_OT_LooperButton(bpy.types.Operator): + '''Trim active armature's animation to a single cycle, given a cyclic animation (such as a walk cycle)''' bl_idname = "mocap.looper" bl_label = "loops animation / sampled mocap data" @@ -383,6 +388,7 @@ class OBJECT_OT_LooperButton(bpy.types.Operator): class OBJECT_OT_DenoiseButton(bpy.types.Operator): + '''Denoise active armature's animation. Good for dealing with 'bad' frames inherent in mocap animation''' bl_idname = "mocap.denoise" bl_label = "Denoises sampled mocap data " @@ -400,6 +406,7 @@ class OBJECT_OT_DenoiseButton(bpy.types.Operator): class OBJECT_OT_LimitDOFButton(bpy.types.Operator): + '''UNIMPLEMENTED: Create limit constraints on the active armature from the selected armature's animation's range of motion''' bl_idname = "mocap.limitdof" bl_label = "Analyzes animations Max/Min DOF and adds hard/soft constraints" @@ -418,6 +425,7 @@ class OBJECT_OT_LimitDOFButton(bpy.types.Operator): class OBJECT_OT_RotateFixArmature(bpy.types.Operator): + '''Realign the active armature's axis system to match Blender (Commonly needed after bvh import)''' bl_idname = "mocap.rotate_fix" bl_label = "Rotates selected armature 90 degrees (fix for bvh import)" @@ -432,6 +440,7 @@ class OBJECT_OT_RotateFixArmature(bpy.types.Operator): class OBJECT_OT_ScaleFixArmature(bpy.types.Operator): + '''Rescale selected armature to match the active animation, for convienence''' bl_idname = "mocap.scale_fix" bl_label = "Scales performer armature to match target armature" @@ -453,6 +462,7 @@ class OBJECT_OT_ScaleFixArmature(bpy.types.Operator): class OBJECT_OT_AddMocapConstraint(bpy.types.Operator): + '''Add a post-retarget fix - useful for fixing certain artifacts following the retarget''' bl_idname = "mocap.addconstraint" bl_label = "Add constraint to target armature" @@ -469,6 +479,7 @@ class OBJECT_OT_AddMocapConstraint(bpy.types.Operator): class OBJECT_OT_RemoveMocapConstraint(bpy.types.Operator): + '''Remove this post-retarget fix''' bl_idname = "mocap.removeconstraint" bl_label = "Removes constraints from target armature" constraint = bpy.props.IntProperty() @@ -492,6 +503,7 @@ class OBJECT_OT_RemoveMocapConstraint(bpy.types.Operator): class OBJECT_OT_BakeMocapConstraints(bpy.types.Operator): + '''Bake all post-retarget fixes to the Retarget Fixes NLA Track''' bl_idname = "mocap.bakeconstraints" bl_label = "Bake all constraints to target armature" @@ -506,6 +518,7 @@ class OBJECT_OT_BakeMocapConstraints(bpy.types.Operator): class OBJECT_OT_UnbakeMocapConstraints(bpy.types.Operator): + '''Unbake all post-retarget fixes - removes the baked data from the Retarget Fixes NLA Track''' bl_idname = "mocap.unbakeconstraints" bl_label = "Unbake all constraints to target armature" -- cgit v1.2.3 From ddbfcacfa074ed301df3dd5e90a9d717ef56c352 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Tue, 19 Jul 2011 16:52:47 +0000 Subject: Added some simple feedback for long processes, currently being printed to the console --- release/scripts/modules/retarget.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 0602de5e596..d05fd71f8ce 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -142,6 +142,8 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene inter_bone.bone.use_inherit_rotation = True for t in range(s_frame, e_frame): + if (t - s_frame) % 10 == 0: + print("First pass: retargeting frame {0}/{1}".format(t, e_frame - s_frame)) scene.frame_set(t) for bone in inter_bones: retargetPerfToInter(bone) @@ -199,6 +201,8 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene): bakeTransform(bone) for t in range(s_frame, e_frame): + if (t - s_frame) % 10 == 0: + print("Second pass: retargeting frame {0}/{1}".format(t, e_frame - s_frame)) scene.frame_set(t) end_bone = end_bones[root] end_bone.location = Vector((0, 0, 0)) @@ -396,11 +400,11 @@ def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): print("cleaning stuff up") perf_obj_mat, enduser_obj_mat = cleanAndStoreObjMat(performer_obj, enduser_obj) turnOffIK(enduser_obj) - print("creating intermediate armature") + print("Creating intermediate armature (for first pass)") inter_obj = createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene) - print("retargeting from intermediate to end user") + print("First pass: retargeting from intermediate to end user") retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene) - print("retargeting root translation and clean up") + print("Second pass: retargeting root translation and clean up") stride_bone = copyTranslation(performer_obj, enduser_obj, feetBones, root, s_frame, e_frame, scene, enduser_obj_mat) IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene) restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone) -- cgit v1.2.3 From 57fe73b3ac6ba6d7a0c3903318d9f0675e18338a Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 20 Jul 2011 00:36:28 +0000 Subject: View All/Selected tools for NLA Editor --- release/scripts/startup/bl_ui/space_nla.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py index 717adb3baa8..78489db6317 100644 --- a/release/scripts/startup/bl_ui/space_nla.py +++ b/release/scripts/startup/bl_ui/space_nla.py @@ -72,7 +72,11 @@ class NLA_MT_view(bpy.types.Menu): layout.separator() layout.operator("anim.previewrange_set") layout.operator("anim.previewrange_clear") - + + layout.separator() + layout.operator("nla.view_all") + layout.operator("nla.view_selected") + layout.separator() layout.operator("screen.area_dupli") layout.operator("screen.screen_full_area") -- cgit v1.2.3 From a08a510d6558f203ee21eefb751752a9fa572cee Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Wed, 20 Jul 2011 21:03:06 +0000 Subject: Two new operators for easier retargeting: Auto scale performer, and a first attempt at auto hiearchy mapping --- release/scripts/modules/mocap_tools.py | 66 ++++++++++++++++++++++++++++++++-- release/scripts/modules/retarget.py | 4 +-- release/scripts/startup/ui_mocap.py | 33 ++++++++++++++--- 3 files changed, 93 insertions(+), 10 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index 1ce76dfbe6f..ed945d45251 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -573,7 +573,67 @@ def scale_fix_armature(performer_obj, enduser_obj): perf_bones = performer_obj.data.bones end_bones = enduser_obj.data.bones - #perf_avg = performer_obj.dimensions + def calculateBoundingRadius(bones): + center = Vector() + for bone in bones: + center += bone.head_local + center /= len(bones) + radius = 0 + for bone in bones: + dist = (bone.head_local - center).length + if dist > radius: + radius = dist + return radius + + perf_rad = calculateBoundingRadius(performer_obj.data.bones) + end_rad = calculateBoundingRadius(enduser_obj.data.bones) #end_avg = enduser_obj.dimensions - #print(perf_avg, end_avg) - #performer_obj.scale /= (perf_avg / end_avg) + factor = end_rad / perf_rad * 1.2 + performer_obj.scale *= factor + + +def guessMapping(performer_obj, enduser_obj): + perf_bones = performer_obj.data.bones + end_bones = enduser_obj.data.bones + + root = perf_bones[0] + + def findBoneSide(bone): + if "Left" in bone: + return "Left", bone.replace("Left", "").lower().replace(".", "") + if "Right" in bone: + return "Right", bone.replace("Right", "").lower().replace(".", "") + if "L" in bone: + return "Left", bone.replace("Left", "").lower().replace(".", "") + if "R" in bone: + return "Right", bone.replace("Right", "").lower().replace(".", "") + return "", bone + + def nameMatch(bone_a, bone_b): + # nameMatch - recieves two strings, returns 2 if they are relatively the same, 1 if they are the same but R and L and 0 if no match at all + side_a, noside_a = findBoneSide(bone_a) + side_b, noside_b = findBoneSide(bone_b) + if side_a == side_b: + if noside_a in noside_b or noside_b in noside_a: + return 2 + else: + if noside_a in noside_b or noside_b in noside_a: + return 1 + return 0 + + def guessSingleMapping(perf_bone): + possible_bones = [end_bones[0]] + while possible_bones: + for end_bone in possible_bones: + match = nameMatch(perf_bone.name, end_bone.name) + if match == 2 and not perf_bone.map: + perf_bone.map = end_bone.name + newPossibleBones = [] + for end_bone in possible_bones: + newPossibleBones += list(end_bone.children) + possible_bones = newPossibleBones + + for child in perf_bone.children: + guessSingleMapping(child) + + guessSingleMapping(root) diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index d05fd71f8ce..f4ab6498e11 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -143,7 +143,7 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene for t in range(s_frame, e_frame): if (t - s_frame) % 10 == 0: - print("First pass: retargeting frame {0}/{1}".format(t, e_frame - s_frame)) + print("First pass: retargeting frame {0}/{1}".format(t, e_frame - s_frame)) scene.frame_set(t) for bone in inter_bones: retargetPerfToInter(bone) @@ -202,7 +202,7 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene): for t in range(s_frame, e_frame): if (t - s_frame) % 10 == 0: - print("Second pass: retargeting frame {0}/{1}".format(t, e_frame - s_frame)) + print("Second pass: retargeting frame {0}/{1}".format(t, e_frame - s_frame)) scene.frame_set(t) end_bone = end_bones[root] end_bone.location = Vector((0, 0, 0)) diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index fe5ae72f280..eabb003bdb9 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -196,16 +196,17 @@ class MocapPanel(bpy.types.Panel): row2.operator("mocap.looper", text='Loop animation') row2.operator("mocap.limitdof", text='Constrain Rig') self.layout.label("Retargeting") - row3 = self.layout.row(align=True) - column1 = row3.column(align=True) - column1.label("Performer Rig") - column2 = row3.column(align=True) - column2.label("Enduser Rig") enduser_obj = bpy.context.active_object performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj] if enduser_obj is None or len(performer_obj) != 1: self.layout.label("Select performer rig and target rig (as active)") else: + self.layout.operator("mocap.guessmapping", text="Guess Hiearchy Mapping") + row3 = self.layout.row(align=True) + column1 = row3.column(align=True) + column1.label("Performer Rig") + column2 = row3.column(align=True) + column2.label("Enduser Rig") performer_obj = performer_obj[0] if performer_obj.data and enduser_obj.data: if performer_obj.data.name in bpy.data.armatures and enduser_obj.data.name in bpy.data.armatures: @@ -532,6 +533,28 @@ class OBJECT_OT_UnbakeMocapConstraints(bpy.types.Operator): return isinstance(context.active_object.data, bpy.types.Armature) +class OBJECT_OT_GuessHierachyMapping(bpy.types.Operator): + '''Attemps to auto figure out hierarchy mapping''' + bl_idname = "mocap.guessmapping" + bl_label = "Attemps to auto figure out hierarchy mapping" + + def execute(self, context): + enduser_obj = bpy.context.active_object + performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj][0] + mocap_tools.guessMapping(performer_obj, enduser_obj) + return {"FINISHED"} + + @classmethod + def poll(cls, context): + if context.active_object: + activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) + performer_obj = [obj for obj in context.selected_objects if obj != context.active_object] + if performer_obj: + return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) + else: + return False + + def register(): bpy.utils.register_module(__name__) -- cgit v1.2.3 From 0adad30e3f5b914d0a101ba6efb07f3fd2d8669e Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 22 Jul 2011 11:20:14 +0000 Subject: Bugfix [#27984] CTRL+T doesn't work in Video Sequencer properly Time-scale drawing wasn't respecting the time unit setting. While working on this, I tried to tweak the grid drawing to a more common setting. It's hardcoded to show lines at every 25 px = once every 25 frames, which is only really fine when FPS=25. Anyways, this works fine enough for the sequencer for now in general usage. --- release/scripts/startup/bl_ui/space_sequencer.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 6a2f2f3a301..fd1b9dc080b 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -114,7 +114,11 @@ class SEQUENCER_MT_view(bpy.types.Menu): layout.operator("sequencer.view_selected") - layout.prop(st, "show_frames") + if st.show_frames: + layout.operator("anim.time_toggle", text="Show Seconds") + else: + layout.operator("anim.time_toggle", text="Show Frames") + layout.prop(st, "show_frame_indicator") if st.display_mode == 'IMAGE': layout.prop(st, "show_safe_margin") -- cgit v1.2.3 From d959f77e7980f77514d499fcbe5884e14785f2e3 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Fri, 22 Jul 2011 18:46:13 +0000 Subject: UI makeover for mocap constraints panel. Now has the look and feel of regular Blender constraints --- release/scripts/startup/ui_mocap.py | 82 ++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 34 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index eabb003bdb9..fb8bbbf9e0f 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -77,6 +77,9 @@ class MocapConstraint(bpy.types.PropertyGroup): default=True, description="Constraint is active", update=setConstraint) + show_expanded = bpy.props.BoolProperty(name="Show Expanded", + default=True, + description="Constraint is fully shown") targetPoint = bpy.props.FloatVectorProperty(name="Point", size=3, subtype="XYZ", default=(0.0, 0.0, 0.0), description="Target of Constraint - Point", @@ -250,41 +253,45 @@ class MocapConstraintsPanel(bpy.types.Panel): if context.active_object.data.name in bpy.data.armatures: enduser_obj = context.active_object enduser_arm = enduser_obj.data - layout.operator("mocap.addconstraint") - layout.operator("mocap.bakeconstraints") - layout.operator("mocap.unbakeconstraints") + layout.operator_menu_enum("mocap.addmocapfix", "type") + bakeRow = layout.row() + bakeRow.operator("mocap.bakeconstraints") + bakeRow.operator("mocap.unbakeconstraints") layout.separator() for i, m_constraint in enumerate(enduser_arm.mocap_constraints): box = layout.box() - box.prop(m_constraint, 'name') - box.prop(m_constraint, 'type') - box.prop_search(m_constraint, 'constrained_bone', enduser_obj.pose, "bones") - if m_constraint.type == "distance" or m_constraint.type == "point": - box.prop_search(m_constraint, 'constrained_boneB', enduser_obj.pose, "bones") - frameRow = box.row() - frameRow.label("Frame Range:") - frameRow.prop(m_constraint, 's_frame') - frameRow.prop(m_constraint, 'e_frame') - smoothRow = box.row() - smoothRow.label("Smoothing:") - smoothRow.prop(m_constraint, 'smooth_in') - smoothRow.prop(m_constraint, 'smooth_out') - targetRow = box.row() - targetLabelCol = targetRow.column() - targetLabelCol.label("Target settings:") - targetPropCol = targetRow.column() - if m_constraint.type == "floor": - targetPropCol.prop_search(m_constraint, 'targetMesh', bpy.data, "objects") - if m_constraint.type == "point" or m_constraint.type == "freeze": - box.prop(m_constraint, 'targetSpace') - if m_constraint.type == "point": - targetPropCol.prop(m_constraint, 'targetPoint') - if m_constraint.type == "distance" or m_constraint.type == "floor": - targetPropCol.prop(m_constraint, 'targetDist') - checkRow = box.row() - checkRow.prop(m_constraint, 'active') - layout.operator("mocap.removeconstraint", text="Remove constraint").constraint = i - layout.separator() + headerRow = box.row() + headerRow.prop(m_constraint, 'show_expanded', text='', icon='TRIA_DOWN' if m_constraint.show_expanded else 'TRIA_RIGHT', emboss=False) + headerRow.prop(m_constraint, 'type', text='') + headerRow.prop(m_constraint, 'name', text='') + headerRow.prop(m_constraint, 'active', icon='MUTE_IPO_ON' if m_constraint.active else'MUTE_IPO_OFF', text='', emboss=False) + headerRow.operator("mocap.removeconstraint", text="", icon='X', emboss=False).constraint = i + if m_constraint.show_expanded: + box.separator() + box.prop_search(m_constraint, 'constrained_bone', enduser_obj.pose, "bones", icon='BONE_DATA') + if m_constraint.type == "distance" or m_constraint.type == "point": + box.prop_search(m_constraint, 'constrained_boneB', enduser_obj.pose, "bones", icon='CONSTRAINT_BONE') + frameRow = box.row() + frameRow.label("Frame Range:") + frameRow.prop(m_constraint, 's_frame') + frameRow.prop(m_constraint, 'e_frame') + smoothRow = box.row() + smoothRow.label("Smoothing:") + smoothRow.prop(m_constraint, 'smooth_in') + smoothRow.prop(m_constraint, 'smooth_out') + targetRow = box.row() + targetLabelCol = targetRow.column() + targetLabelCol.label("Target settings:") + targetPropCol = targetRow.column() + if m_constraint.type == "floor": + targetPropCol.prop_search(m_constraint, 'targetMesh', bpy.data, "objects") + if m_constraint.type == "point" or m_constraint.type == "freeze": + box.prop(m_constraint, 'targetSpace') + if m_constraint.type == "point": + targetPropCol.prop(m_constraint, 'targetPoint') + if m_constraint.type == "distance" or m_constraint.type == "floor": + targetPropCol.prop(m_constraint, 'targetDist') + layout.separator() class OBJECT_OT_RetargetButton(bpy.types.Operator): @@ -462,15 +469,22 @@ class OBJECT_OT_ScaleFixArmature(bpy.types.Operator): return False -class OBJECT_OT_AddMocapConstraint(bpy.types.Operator): +class MOCAP_OT_AddMocapFix(bpy.types.Operator): '''Add a post-retarget fix - useful for fixing certain artifacts following the retarget''' - bl_idname = "mocap.addconstraint" + bl_idname = "mocap.addmocapfix" bl_label = "Add constraint to target armature" + type = bpy.props.EnumProperty(name="Type of constraint", + items=[("point", "Maintain Position", "Bone is at a specific point"), + ("freeze", "Maintain Position at frame", "Bone does not move from location specified in target frame"), + ("floor", "Stay above", "Bone does not cross specified mesh object eg floor"), + ("distance", "Maintain distance", "Target bones maintained specified distance")], + description="Type of constraint") def execute(self, context): enduser_obj = bpy.context.active_object enduser_arm = enduser_obj.data new_mcon = enduser_arm.mocap_constraints.add() + new_mcon.type = self.type return {"FINISHED"} @classmethod -- cgit v1.2.3 From fd79de0bb3f8b98cdbf973beababec83a2bc399e Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Fri, 22 Jul 2011 18:46:59 +0000 Subject: NLA Track for custom user tweaks is now added after retargeting --- release/scripts/modules/retarget.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index f4ab6498e11..ecf627798c4 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -21,6 +21,7 @@ import bpy from mathutils import * from math import radians, acos +import cProfile def hasIKConstraint(pose_bone): @@ -44,6 +45,7 @@ def createDictionary(perf_arm, end_arm): end_bone = end_arm.bones[perf_bone.map] newMap = end_bone.reverseMap.add() newMap.name = perf_bone.name + end_bone.foot = perf_bone.foot #root is the root of the enduser root = end_arm.bones[0].name @@ -386,6 +388,12 @@ def NLASystemInitialize(enduser_obj, s_frame): constraintAction = bpy.data.actions.new("Mocap constraints") constraintStrip = constraintTrack.strips.new("Mocap constraints", s_frame, constraintAction) constraintStrip.extrapolation = "NOTHING" + userTrack = anim_data.nla_tracks.new() + userTrack.name = "Mocap manual fix" + userAction = bpy.data.actions.new("Mocap manual fix") + userStrip = userTrack.strips.new("Mocap manual fix", s_frame, userAction) + userStrip.extrapolation = "HOLD" + #userStrip.blend_type = "MULITPLY" - doesn't work due to work, will be activated soon anim_data.nla_tracks.active = constraintTrack anim_data.action = constraintAction anim_data.action_extrapolation = "NOTHING" @@ -414,6 +422,5 @@ def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): NLASystemInitialize(enduser_obj, s_frame) print("retargeting done!") - if __name__ == "__main__": totalRetarget() -- cgit v1.2.3 From 1f65b3b1a8f5ccc54a794ed0d6f8cf2d3e2c5a36 Mon Sep 17 00:00:00 2001 From: Mitchell Stokes Date: Tue, 26 Jul 2011 06:10:05 +0000 Subject: BGE Animations: Adding a new choice for vertex deformation for armatures, which can be found in the Armature's Skeleton panel by the Deform options. Before only Blender's armature_deform_verts() was used. Now users can choose a vertex deformation function that is optimized for the BGE. At the moment it is mostly a copy of armature_deform_verts() with various chunks of code removed, and the BLI_math code was replaced with Eigen2. In my test scene, the new function offered about a 40% improvement over armature_deform_verts() (17~19ms rasterizer to 11~12ms). The only current limitation that I'm aware of if that B-Bone segments are not supported in the BGE version, and I will probably leave it out. I would like to also limit the BGE version to 4 weights to make things easier for a GPU version, but this may just make things slower (sorting weights to find the top 4). --- release/scripts/startup/bl_ui/properties_data_armature.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py index eae7f9e9824..00ccd4ce08b 100644 --- a/release/scripts/startup/bl_ui/properties_data_armature.py +++ b/release/scripts/startup/bl_ui/properties_data_armature.py @@ -70,6 +70,9 @@ class DATA_PT_skeleton(ArmatureButtonsPanel, bpy.types.Panel): flow.prop(arm, "use_deform_envelopes", text="Envelopes") flow.prop(arm, "use_deform_preserve_volume", text="Quaternion") + if context.scene.render.engine == "BLENDER_GAME": + col = layout.column() + col.prop(arm, "vert_deformer") class DATA_PT_display(ArmatureButtonsPanel, bpy.types.Panel): bl_label = "Display" -- cgit v1.2.3 From bd6ca0570e089afc1d29b4f18b8bb6cc086545ea Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Thu, 28 Jul 2011 13:58:59 +0000 Subject: 3D Audio GSoC: Implemented basic audio animation. * AnimatableProperty: Propper cache writing and spline interpolation for reading (the solution for stair steps in audio animation) * Animatable properties so far are: volume, pitch, panning * Users note: Changing the pitch of a sound results in wrong seeking, due to the resulting playback length difference. * Users note: Panning only works for mono sources, values are in the range [-2..2], this basically controls the angle of the sound, 0 is front, -1 left, 1 right and 2 and -2 are back. Typical stereo panning only supports [-1..1]. * Disabled animation of audio related ffmpeg output parameters. * Scene Audio Panel: 3D Listener settings also for Renderer, new Volume property (animatable!), Update/Bake buttons for animation problems, moved sampling rate and channel count here --- release/scripts/startup/bl_ui/properties_game.py | 15 ------------- release/scripts/startup/bl_ui/properties_render.py | 3 --- release/scripts/startup/bl_ui/properties_scene.py | 26 ++++++++++++++++++++++ release/scripts/startup/bl_ui/space_sequencer.py | 2 ++ 4 files changed, 28 insertions(+), 18 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py index 0c07451b3b2..58b2cacfbcc 100644 --- a/release/scripts/startup/bl_ui/properties_game.py +++ b/release/scripts/startup/bl_ui/properties_game.py @@ -360,21 +360,6 @@ class RENDER_PT_game_display(RenderButtonsPanel, bpy.types.Panel): flow.prop(gs, "show_mouse", text="Mouse Cursor") -class RENDER_PT_game_sound(RenderButtonsPanel, bpy.types.Panel): - bl_label = "Sound" - COMPAT_ENGINES = {'BLENDER_GAME'} - - def draw(self, context): - layout = self.layout - - scene = context.scene - - layout.prop(scene, "audio_distance_model") - - layout.prop(scene, "audio_doppler_speed", text="Speed") - layout.prop(scene, "audio_doppler_factor") - - class WorldButtonsPanel(): bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index 3ba54aa67c6..9b4b8089c4a 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -595,11 +595,8 @@ class RENDER_PT_encoding(RenderButtonsPanel, bpy.types.Panel): col = split.column() col.prop(rd, "ffmpeg_audio_bitrate") - col.prop(rd, "ffmpeg_audio_mixrate") - col = split.column() col.prop(rd, "ffmpeg_audio_volume", slider=True) - col.prop(rd, "ffmpeg_audio_channels") class RENDER_PT_bake(RenderButtonsPanel, bpy.types.Panel): diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py index e2dc9de064f..aec9d88511c 100644 --- a/release/scripts/startup/bl_ui/properties_scene.py +++ b/release/scripts/startup/bl_ui/properties_scene.py @@ -43,6 +43,32 @@ class SCENE_PT_scene(SceneButtonsPanel, bpy.types.Panel): layout.prop(scene, "background_set", text="Background") +class SCENE_PT_audio(SceneButtonsPanel, bpy.types.Panel): + bl_label = "Audio" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + + def draw(self, context): + layout = self.layout + scene = context.scene + rd = context.scene.render + + layout.prop(scene, "audio_distance_model") + + layout.prop(scene, "audio_doppler_speed", text="Speed") + layout.prop(scene, "audio_doppler_factor") + + layout.prop(scene, "audio_volume") + layout.operator("sound.update_animation_flags") + layout.operator("sound.bake_animation") + + split = layout.split() + + col = split.column() + col.prop(rd, "ffmpeg_audio_mixrate", text="Rate") + col = split.column() + col.prop(rd, "ffmpeg_audio_channels", text="") + + class SCENE_PT_unit(SceneButtonsPanel, bpy.types.Panel): bl_label = "Units" COMPAT_ENGINES = {'BLENDER_RENDER'} diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index fd1b9dc080b..5320297dce2 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -640,6 +640,8 @@ class SEQUENCER_PT_sound(SequencerButtonsPanel, bpy.types.Panel): layout.prop(strip, "volume") layout.prop(strip, "attenuation") + layout.prop(strip, "pitch") + layout.prop(strip, "pan") col = layout.column(align=True) col.label(text="Trim Duration:") -- cgit v1.2.3 From ce1c78e18bf41115a8a149dd85115292c1919bea Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Fri, 29 Jul 2011 18:23:16 +0000 Subject: Changed name of Mocap constraints to mocap fixes, for user clarity. --- release/scripts/modules/mocap_constraints.py | 6 ++--- release/scripts/modules/retarget.py | 6 ++--- release/scripts/startup/ui_mocap.py | 34 ++++++++++++++-------------- 3 files changed, 23 insertions(+), 23 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py index 7a49a96b7b1..25e78d2bf9b 100644 --- a/release/scripts/modules/mocap_constraints.py +++ b/release/scripts/modules/mocap_constraints.py @@ -59,7 +59,7 @@ def addNewConstraint(m_constraint, cons_obj): c_type = "LIMIT_LOCATION" #create and store the new constraint within m_constraint real_constraint = cons_obj.constraints.new(c_type) - real_constraint.name = "Mocap constraint " + str(len(cons_obj.constraints)) + real_constraint.name = "Mocap fix " + str(len(cons_obj.constraints)) m_constraint.real_constraint_bone = consObjToBone(cons_obj) m_constraint.real_constraint = real_constraint.name #set the rest of the constraint properties @@ -336,7 +336,7 @@ def bakeAllConstraints(obj, s_frame, e_frame, bones): simpleBake += [end_bone] for bone in selectedBones: bone.bone.select = True - constraintTrack = obj.animation_data.nla_tracks["Mocap constraints"] + constraintTrack = obj.animation_data.nla_tracks["Mocap fixes"] constraintStrip = constraintTrack.strips[0] constraintStrip.action_frame_start = s_frame constraintStrip.action_frame_end = e_frame @@ -375,7 +375,7 @@ def unbakeConstraints(context): obj = context.active_object bones = obj.pose.bones scene = bpy.context.scene - constraintTrack = obj.animation_data.nla_tracks["Mocap constraints"] + constraintTrack = obj.animation_data.nla_tracks["Mocap fixes"] constraintStrip = constraintTrack.strips[0] action = constraintStrip.action # delete the fcurves on the strip diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index ecf627798c4..bec7b8aaa3e 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -384,9 +384,9 @@ def NLASystemInitialize(enduser_obj, s_frame): mocapTrack.name = "Base Mocap Track" mocapStrip = mocapTrack.strips.new("Base Mocap", s_frame, mocapAction) constraintTrack = anim_data.nla_tracks.new() - constraintTrack.name = "Mocap constraints" - constraintAction = bpy.data.actions.new("Mocap constraints") - constraintStrip = constraintTrack.strips.new("Mocap constraints", s_frame, constraintAction) + constraintTrack.name = "Mocap fixes" + constraintAction = bpy.data.actions.new("Mocap fixes") + constraintStrip = constraintTrack.strips.new("Mocap fixes", s_frame, constraintAction) constraintStrip.extrapolation = "NOTHING" userTrack = anim_data.nla_tracks.new() userTrack.name = "Mocap manual fix" diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index fb8bbbf9e0f..044e13e81f5 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -40,8 +40,8 @@ from mocap_constraints import * class MocapConstraint(bpy.types.PropertyGroup): name = bpy.props.StringProperty(name="Name", - default="Mocap Constraint", - description="Name of Mocap Constraint", + default="Mocap Fix", + description="Name of Mocap Fix", update=setConstraint) constrained_bone = bpy.props.StringProperty(name="Bone", default="", @@ -53,11 +53,11 @@ class MocapConstraint(bpy.types.PropertyGroup): update=setConstraint) s_frame = bpy.props.IntProperty(name="S", default=1, - description="Start frame of constraint", + description="Start frame of Fix", update=setConstraint) e_frame = bpy.props.IntProperty(name="E", default=500, - description="End frame of constrain", + description="End frame of Fix", update=setConstraint) smooth_in = bpy.props.IntProperty(name="In", default=10, @@ -71,22 +71,22 @@ class MocapConstraint(bpy.types.PropertyGroup): min=0) targetMesh = bpy.props.StringProperty(name="Mesh", default="", - description="Target of Constraint - Mesh (optional, depends on type)", + description="Target of Fix - Mesh (optional, depends on type)", update=setConstraint) active = bpy.props.BoolProperty(name="Active", default=True, - description="Constraint is active", + description="Fix is active", update=setConstraint) show_expanded = bpy.props.BoolProperty(name="Show Expanded", default=True, - description="Constraint is fully shown") + description="Fix is fully shown") targetPoint = bpy.props.FloatVectorProperty(name="Point", size=3, subtype="XYZ", default=(0.0, 0.0, 0.0), - description="Target of Constraint - Point", + description="Target of Fix - Point", update=setConstraint) targetDist = bpy.props.FloatProperty(name="Offset", default=0.0, - description="Distance and Floor Constraints - Desired offset", + description="Distance and Floor Fixes - Desired offset", update=setConstraint) targetSpace = bpy.props.EnumProperty( items=[("WORLD", "World Space", "Evaluate target in global space"), @@ -100,7 +100,7 @@ class MocapConstraint(bpy.types.PropertyGroup): ("freeze", "Maintain Position at frame", "Bone does not move from location specified in target frame"), ("floor", "Stay above", "Bone does not cross specified mesh object eg floor"), ("distance", "Maintain distance", "Target bones maintained specified distance")], - description="Type of constraint", + description="Type of Fix", update=updateConstraintBoneType) real_constraint = bpy.props.StringProperty() real_constraint_bone = bpy.props.StringProperty() @@ -241,7 +241,7 @@ class MocapPanel(bpy.types.Panel): class MocapConstraintsPanel(bpy.types.Panel): #Motion capture constraints panel - bl_label = "Mocap constraints" + bl_label = "Mocap Fixes" bl_space_type = "PROPERTIES" bl_region_type = "WINDOW" bl_context = "object" @@ -472,13 +472,13 @@ class OBJECT_OT_ScaleFixArmature(bpy.types.Operator): class MOCAP_OT_AddMocapFix(bpy.types.Operator): '''Add a post-retarget fix - useful for fixing certain artifacts following the retarget''' bl_idname = "mocap.addmocapfix" - bl_label = "Add constraint to target armature" - type = bpy.props.EnumProperty(name="Type of constraint", + bl_label = "Add Mocap Fix to target armature" + type = bpy.props.EnumProperty(name="Type of Fix", items=[("point", "Maintain Position", "Bone is at a specific point"), ("freeze", "Maintain Position at frame", "Bone does not move from location specified in target frame"), ("floor", "Stay above", "Bone does not cross specified mesh object eg floor"), ("distance", "Maintain distance", "Target bones maintained specified distance")], - description="Type of constraint") + description="Type of fix") def execute(self, context): enduser_obj = bpy.context.active_object @@ -496,7 +496,7 @@ class MOCAP_OT_AddMocapFix(bpy.types.Operator): class OBJECT_OT_RemoveMocapConstraint(bpy.types.Operator): '''Remove this post-retarget fix''' bl_idname = "mocap.removeconstraint" - bl_label = "Removes constraints from target armature" + bl_label = "Removes fixes from target armature" constraint = bpy.props.IntProperty() def execute(self, context): @@ -520,7 +520,7 @@ class OBJECT_OT_RemoveMocapConstraint(bpy.types.Operator): class OBJECT_OT_BakeMocapConstraints(bpy.types.Operator): '''Bake all post-retarget fixes to the Retarget Fixes NLA Track''' bl_idname = "mocap.bakeconstraints" - bl_label = "Bake all constraints to target armature" + bl_label = "Bake all fixes to target armature" def execute(self, context): bakeConstraints(context) @@ -535,7 +535,7 @@ class OBJECT_OT_BakeMocapConstraints(bpy.types.Operator): class OBJECT_OT_UnbakeMocapConstraints(bpy.types.Operator): '''Unbake all post-retarget fixes - removes the baked data from the Retarget Fixes NLA Track''' bl_idname = "mocap.unbakeconstraints" - bl_label = "Unbake all constraints to target armature" + bl_label = "Unbake all fixes to target armature" def execute(self, context): unbakeConstraints(context) -- cgit v1.2.3 From 3e85ec432ef050563d75488eca3049b77497153d Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Mon, 1 Aug 2011 11:44:20 +0000 Subject: 3D Audio GSoC: Adds new speaker object type. Notes: * Needs some nice icons * Quickily review by Joshua Leung (5 mins) * Properties UI updated (with help of Thomans Dinges) * Speakers have their own theme color * No real audio functionality yet. * Minor bug regarding lamps/lattices fixed in interface_templates.c I personality tested: * Creation, Deletion, Duplication * Saving, Loading * Library linking (incl. make local) * Tracking * Dope Sheet, Outliner * Animation * Drawing (incl. Theme) --- release/scripts/modules/bpy_types.py | 2 +- release/scripts/startup/bl_ui/__init__.py | 1 + .../startup/bl_ui/properties_data_speaker.py | 129 +++++++++++++++++++++ release/scripts/startup/bl_ui/properties_scene.py | 55 ++------- release/scripts/startup/bl_ui/space_dopesheet.py | 2 + release/scripts/startup/bl_ui/space_info.py | 3 + 6 files changed, 145 insertions(+), 47 deletions(-) create mode 100644 release/scripts/startup/bl_ui/properties_data_speaker.py (limited to 'release') diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 056899d7bda..75b199dcc26 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -57,7 +57,7 @@ class Library(bpy_types.ID): "curves", "grease_pencil", "groups", "images", \ "lamps", "lattices", "materials", "metaballs", \ "meshes", "node_groups", "objects", "scenes", \ - "sounds", "textures", "texts", "fonts", "worlds" + "sounds", "speakers", "textures", "texts", "fonts", "worlds" return tuple(id_block for attr in attr_links for id_block in getattr(bpy.data, attr) if id_block.library == self) diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py index bf63c6071b9..5fab3b7fd38 100644 --- a/release/scripts/startup/bl_ui/__init__.py +++ b/release/scripts/startup/bl_ui/__init__.py @@ -36,6 +36,7 @@ _modules = ( "properties_data_mesh", "properties_data_metaball", "properties_data_modifier", + "properties_data_speaker", "properties_game", "properties_material", "properties_object_constraint", diff --git a/release/scripts/startup/bl_ui/properties_data_speaker.py b/release/scripts/startup/bl_ui/properties_data_speaker.py new file mode 100644 index 00000000000..45f2fa5d1f7 --- /dev/null +++ b/release/scripts/startup/bl_ui/properties_data_speaker.py @@ -0,0 +1,129 @@ +# ##### 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 ##### + +# +import bpy +from rna_prop_ui import PropertyPanel + + +class DataButtonsPanel(): + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + + @classmethod + def poll(cls, context): + engine = context.scene.render.engine + return context.speaker and (engine in cls.COMPAT_ENGINES) + + +class DATA_PT_context_speaker(DataButtonsPanel, bpy.types.Panel): + bl_label = "" + bl_options = {'HIDE_HEADER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + + def draw(self, context): + layout = self.layout + + ob = context.object + speaker = context.speaker + space = context.space_data + + split = layout.split(percentage=0.65) + + if ob: + split.template_ID(ob, "data") + elif speaker: + split.template_ID(space, "pin_id") + + +class DATA_PT_speaker(DataButtonsPanel, bpy.types.Panel): + bl_label = "Sound" + COMPAT_ENGINES = {'BLENDER_RENDER'} + + def draw(self, context): + layout = self.layout + + speaker = context.speaker + + split = layout.split(percentage=0.75) + + split.template_ID(speaker, "sound", open="sound.open") + split.prop(speaker, "muted") + + split = layout.split() + + row = split.row() + + row.prop(speaker, "volume") + row.prop(speaker, "pitch") + + +class DATA_PT_distance(DataButtonsPanel, bpy.types.Panel): + bl_label = "Distance" + COMPAT_ENGINES = {'BLENDER_RENDER'} + + def draw(self, context): + layout = self.layout + + speaker = context.speaker + + split = layout.split() + col = split.column() + + col.label("Volume:") + col.prop(speaker, "volume_min", text="Minimum") + col.prop(speaker, "volume_max", text="Maximum") + col.prop(speaker, "attenuation") + + col = split.column() + + col.label("Distance:") + col.prop(speaker, "distance_max", text="Maximum") + col.prop(speaker, "distance_reference", text="Reference") + + +class DATA_PT_cone(DataButtonsPanel, bpy.types.Panel): + bl_label = "Cone" + COMPAT_ENGINES = {'BLENDER_RENDER'} + + def draw(self, context): + layout = self.layout + + speaker = context.speaker + + split = layout.split() + col = split.column() + + col.label("Angle:") + col.prop(speaker, "cone_angle_outer", text="Outer") + col.prop(speaker, "cone_angle_inner", text="Inner") + + col = split.column() + + col.label("Volume:") + col.prop(speaker, "cone_volume_outer", text="Outer") + + +class DATA_PT_custom_props_speaker(DataButtonsPanel, PropertyPanel, bpy.types.Panel): + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + _context_path = "object.data" + _property_type = bpy.types.Speaker + +if __name__ == "__main__": # only for live edit. + bpy.utils.register_module(__name__) diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py index aec9d88511c..a9310fcc532 100644 --- a/release/scripts/startup/bl_ui/properties_scene.py +++ b/release/scripts/startup/bl_ui/properties_scene.py @@ -51,22 +51,24 @@ class SCENE_PT_audio(SceneButtonsPanel, bpy.types.Panel): layout = self.layout scene = context.scene rd = context.scene.render - - layout.prop(scene, "audio_distance_model") - - layout.prop(scene, "audio_doppler_speed", text="Speed") - layout.prop(scene, "audio_doppler_factor") layout.prop(scene, "audio_volume") - layout.operator("sound.update_animation_flags") layout.operator("sound.bake_animation") split = layout.split() col = split.column() - col.prop(rd, "ffmpeg_audio_mixrate", text="Rate") + + col.label("Listener:") + col.prop(scene, "audio_distance_model", text="") + col.prop(scene, "audio_doppler_speed", text="Speed") + col.prop(scene, "audio_doppler_factor", text="Doppler") + col = split.column() + + col.label("Format:") col.prop(rd, "ffmpeg_audio_channels", text="") + col.prop(rd, "ffmpeg_audio_mixrate", text="Rate") class SCENE_PT_unit(SceneButtonsPanel, bpy.types.Panel): @@ -102,7 +104,6 @@ class SCENE_PT_keying_sets(SceneButtonsPanel, bpy.types.Panel): col = row.column(align=True) col.operator("anim.keying_set_add", icon='ZOOMIN', text="") col.operator("anim.keying_set_remove", icon='ZOOMOUT', text="") - col.menu("SCENE_MT_keying_set_specials", icon='DOWNARROW_HLT', text="") ks = scene.keying_sets.active if ks and ks.is_path_absolute: @@ -121,14 +122,6 @@ class SCENE_PT_keying_sets(SceneButtonsPanel, bpy.types.Panel): col.prop(ks, "bl_options") -class SCENE_MT_keying_set_specials(bpy.types.Menu): - bl_label = "Keying Set Specials" - - def draw(self, context): - layout = self.layout - - layout.operator("anim.keying_set_import", text="Import From File") - class SCENE_PT_keying_set_paths(SceneButtonsPanel, bpy.types.Panel): bl_label = "Active Keying Set" @@ -233,36 +226,6 @@ class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, bpy.types.Panel): # XXX, move operator to op/ dir -class ANIM_OT_keying_set_import(bpy.types.Operator): - "Import Keying Set from a python script." - bl_idname = "anim.keying_set_import" - bl_label = "Import Keying Set from File" - - filepath = bpy.props.StringProperty(name="File Path", description="Filepath to read file from.") - filter_folder = bpy.props.BoolProperty(name="Filter folders", description="", default=True, options={'HIDDEN'}) - filter_text = bpy.props.BoolProperty(name="Filter text", description="", default=True, options={'HIDDEN'}) - filter_python = bpy.props.BoolProperty(name="Filter python", description="", default=True, options={'HIDDEN'}) - - def execute(self, context): - if not self.filepath: - raise Exception("Filepath not set.") - - f = open(self.filepath, "r") - if not f: - raise Exception("Could not open file.") - - # lazy way of loading and running this file... - exec(compile(f.read(), self.filepath, 'exec')) - - f.close() - - return {'FINISHED'} - - def invoke(self, context, event): - wm = context.window_manager - wm.fileselect_add(self) - return {'RUNNING_MODAL'} - class ANIM_OT_keying_set_export(bpy.types.Operator): "Export Keying Set to a python script." bl_idname = "anim.keying_set_export" diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index b4f196dab74..646a085f3f7 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -86,6 +86,8 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False): 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="") ####################################### diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index f66cee7f431..eba2581252a 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -292,6 +292,9 @@ class INFO_MT_add(bpy.types.Menu): layout.operator_menu_enum("object.lamp_add", "type", text="Lamp", icon='OUTLINER_OB_LAMP') layout.separator() + layout.operator("object.speaker_add", text="Speaker", icon='SPEAKER') + layout.separator() + layout.operator_menu_enum("object.effector_add", "type", text="Force Field", icon='OUTLINER_OB_EMPTY') layout.separator() -- cgit v1.2.3 From 827f92497e8b3044811b8c79d3706ea660a4e123 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Tue, 2 Aug 2011 17:08:49 +0000 Subject: Other bone functionality coded for point post retarget fix. You can now set the point to be offset from a second bone, i.e. follow other bone's path --- release/scripts/modules/mocap_constraints.py | 34 +++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py index 25e78d2bf9b..7ac2387d787 100644 --- a/release/scripts/modules/mocap_constraints.py +++ b/release/scripts/modules/mocap_constraints.py @@ -189,11 +189,17 @@ def setConstraint(m_constraint, context): #frame changing section setConstraintFraming(m_constraint, context) - + s, e = m_constraint.s_frame, m_constraint.e_frame + s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out + s -= s_in + e += s_out #Set the blender constraint parameters if m_constraint.type == "point": - constraint_settings = False - real_constraint.owner_space = m_constraint.targetSpace + constraint_settings = False # are fix settings keyframed? + if not m_constraint.targetSpace == "constrained_boneB": + real_constraint.owner_space = m_constraint.targetSpace + else: + real_constraint.owner_space = "LOCAL" if obj.data.animation_data: if obj.data.animation_data.action: path = m_constraint.path_from_id("targetPoint") @@ -207,6 +213,27 @@ def setConstraint(m_constraint, context): copyFCurve(curve, m_fcurves[1]) for curve in zCurves: copyFCurve(curve, m_fcurves[2]) + if m_constraint.targetSpace == "constrained_boneB" and m_constraint.constrained_boneB: + c_frame = context.scene.frame_current + bakedPos = {} + src_bone = bones[m_constraint.constrained_boneB] + if not constraint_settings: + xCurves, yCurves, zCurves = createConstraintFCurves(cons_obj, obj, real_constraint) + print("please wait a moment, calculating fix") + for t in range(s, e): + context.scene.frame_set(t) + src_bone_pos = src_bone.matrix.to_translation() + bakedPos[t] = src_bone_pos + m_constraint.targetPoint # final position for constrained bone in object space + context.scene.frame_set(c_frame) + for frame in bakedPos.keys(): + pos = bakedPos[frame] + for xCurve in xCurves: + xCurve.keyframe_points.insert(frame=frame, value=pos.x) + for yCurve in yCurves: + yCurve.keyframe_points.insert(frame=frame, value=pos.y) + for zCurve in zCurves: + zCurve.keyframe_points.insert(frame=frame, value=pos.z) + if not constraint_settings: x, y, z = m_constraint.targetPoint real_constraint.max_x = x @@ -260,6 +287,7 @@ def setConstraint(m_constraint, context): bakedPos = {} floor = bpy.data.objects[m_constraint.targetMesh] c_frame = context.scene.frame_current + print("please wait a moment, calculating fix") for t in range(s, e): context.scene.frame_set(t) axis = Vector((0, 0, 100)) * obj.matrix_world.to_3x3() -- cgit v1.2.3 From 2f2a95efb888f123602e89ba93f9395d85b75892 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Tue, 2 Aug 2011 17:10:01 +0000 Subject: Sane defaults for post-retarget fix's framing, and ui bugfix (active icon was showing opposite of real active state) --- release/scripts/startup/ui_mocap.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 044e13e81f5..f31b580411a 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -52,11 +52,11 @@ class MocapConstraint(bpy.types.PropertyGroup): description="Other Constrained Bone (optional, depends on type)", update=setConstraint) s_frame = bpy.props.IntProperty(name="S", - default=1, + default=bpy.context.scene.frame_start, description="Start frame of Fix", update=setConstraint) e_frame = bpy.props.IntProperty(name="E", - default=500, + default=bpy.context.scene.frame_end, description="End frame of Fix", update=setConstraint) smooth_in = bpy.props.IntProperty(name="In", @@ -264,7 +264,7 @@ class MocapConstraintsPanel(bpy.types.Panel): headerRow.prop(m_constraint, 'show_expanded', text='', icon='TRIA_DOWN' if m_constraint.show_expanded else 'TRIA_RIGHT', emboss=False) headerRow.prop(m_constraint, 'type', text='') headerRow.prop(m_constraint, 'name', text='') - headerRow.prop(m_constraint, 'active', icon='MUTE_IPO_ON' if m_constraint.active else'MUTE_IPO_OFF', text='', emboss=False) + headerRow.prop(m_constraint, 'active', icon='MUTE_IPO_ON' if not m_constraint.active else'MUTE_IPO_OFF', text='', emboss=False) headerRow.operator("mocap.removeconstraint", text="", icon='X', emboss=False).constraint = i if m_constraint.show_expanded: box.separator() -- cgit v1.2.3 From 6d7490632f13f9744c6b3e507c838a34f3481846 Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Wed, 3 Aug 2011 09:25:40 +0000 Subject: 3D Audio GSoC: * Minor audaspace library improvements. * Considering location, velocity and orientation in AUD_SequencerReader and AUD_SequencerHandle. * Bugfix: Maximum and Minimum volume weren't used before in the software device. * Bugfix: Adding speaker objects via info space crashed. * Listener settings now get updated in the audio system. --- release/scripts/startup/bl_ui/space_info.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index eba2581252a..6c3dc7517c5 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -287,14 +287,14 @@ class INFO_MT_add(bpy.types.Menu): layout.operator("object.add", text="Empty", icon='OUTLINER_OB_EMPTY').type = 'EMPTY' layout.separator() + layout.operator("object.speaker_add", text="Speaker", icon='SPEAKER') + layout.separator() + layout.operator("object.camera_add", text="Camera", icon='OUTLINER_OB_CAMERA') layout.operator_context = 'EXEC_SCREEN' layout.operator_menu_enum("object.lamp_add", "type", text="Lamp", icon='OUTLINER_OB_LAMP') layout.separator() - layout.operator("object.speaker_add", text="Speaker", icon='SPEAKER') - layout.separator() - layout.operator_menu_enum("object.effector_add", "type", text="Force Field", icon='OUTLINER_OB_EMPTY') layout.separator() -- cgit v1.2.3 From fde1dc0fb2fd6275e85821f12a6bc362cc6a2d38 Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Wed, 3 Aug 2011 13:34:49 +0000 Subject: Speaker Object icons, thanks Phil Gosch. --- release/datafiles/blenderbuttons | Bin 213035 -> 215334 bytes release/scripts/startup/bl_ui/space_info.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'release') diff --git a/release/datafiles/blenderbuttons b/release/datafiles/blenderbuttons index 4a308e7151d..4c064182a8c 100644 Binary files a/release/datafiles/blenderbuttons and b/release/datafiles/blenderbuttons differ diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index 6c3dc7517c5..90afc062af4 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -287,7 +287,7 @@ class INFO_MT_add(bpy.types.Menu): layout.operator("object.add", text="Empty", icon='OUTLINER_OB_EMPTY').type = 'EMPTY' layout.separator() - layout.operator("object.speaker_add", text="Speaker", icon='SPEAKER') + layout.operator("object.speaker_add", text="Speaker", icon='OUTLINER_OB_SPEAKER') layout.separator() layout.operator("object.camera_add", text="Camera", icon='OUTLINER_OB_CAMERA') -- cgit v1.2.3 From b9039168fee70db8e9809fad36be0f6209b081e4 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Wed, 3 Aug 2011 18:13:44 +0000 Subject: Fixed coding style to conform to pep8 --- release/scripts/modules/mocap_constraints.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py index 7ac2387d787..8fd42d17392 100644 --- a/release/scripts/modules/mocap_constraints.py +++ b/release/scripts/modules/mocap_constraints.py @@ -195,7 +195,7 @@ def setConstraint(m_constraint, context): e += s_out #Set the blender constraint parameters if m_constraint.type == "point": - constraint_settings = False # are fix settings keyframed? + constraint_settings = False # are fix settings keyframed? if not m_constraint.targetSpace == "constrained_boneB": real_constraint.owner_space = m_constraint.targetSpace else: @@ -223,7 +223,7 @@ def setConstraint(m_constraint, context): for t in range(s, e): context.scene.frame_set(t) src_bone_pos = src_bone.matrix.to_translation() - bakedPos[t] = src_bone_pos + m_constraint.targetPoint # final position for constrained bone in object space + bakedPos[t] = src_bone_pos + m_constraint.targetPoint # final position for constrained bone in object space context.scene.frame_set(c_frame) for frame in bakedPos.keys(): pos = bakedPos[frame] @@ -233,7 +233,7 @@ def setConstraint(m_constraint, context): yCurve.keyframe_points.insert(frame=frame, value=pos.y) for zCurve in zCurves: zCurve.keyframe_points.insert(frame=frame, value=pos.z) - + if not constraint_settings: x, y, z = m_constraint.targetPoint real_constraint.max_x = x -- cgit v1.2.3 From ab3fc2fa5c98fbf98d94d9e6e464eff8ac8370fb Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Wed, 3 Aug 2011 18:16:32 +0000 Subject: Added functions for toggling DOF Constraints on user rig based on range of motion in motion capture clip. Limit Rotation constraints are added based on the min and max of each DOF of each bone in its local space --- release/scripts/modules/mocap_tools.py | 71 +++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index ed945d45251..703db4477ba 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -18,7 +18,7 @@ # -from math import hypot, sqrt, isfinite, radians +from math import hypot, sqrt, isfinite, radians, pi import bpy import time from mathutils import Vector, Matrix @@ -637,3 +637,72 @@ def guessMapping(performer_obj, enduser_obj): guessSingleMapping(child) guessSingleMapping(root) + + +def limit_dof(context, performer_obj, enduser_obj): + limitDict = {} + perf_bones = [bone for bone in performer_obj.pose.bones if bone.bone.map] + c_frame = context.scene.frame_current + for bone in perf_bones: + limitDict[bone.bone.map] = [1000, 1000, 1000, -1000, -1000, -1000] + for t in range(context.scene.frame_start, context.scene.frame_end): + context.scene.frame_set(t) + for bone in perf_bones: + end_bone = enduser_obj.pose.bones[bone.bone.map] + bake_matrix = bone.matrix + rest_matrix = end_bone.bone.matrix_local + + if end_bone.parent and end_bone.bone.use_inherit_rotation: + srcParent = bone.parent + parent_mat = srcParent.matrix + parent_rest = end_bone.parent.bone.matrix_local + parent_rest_inv = parent_rest.copy() + parent_rest_inv.invert() + parent_mat_inv = parent_mat.copy() + parent_mat_inv.invert() + bake_matrix = parent_mat_inv * bake_matrix + rest_matrix = parent_rest_inv * rest_matrix + + rest_matrix_inv = rest_matrix.copy() + rest_matrix_inv.invert() + bake_matrix = rest_matrix_inv * bake_matrix + + mat = bake_matrix + euler = mat.to_euler() + limitDict[bone.bone.map][0] = min(limitDict[bone.bone.map][0], euler.x) + limitDict[bone.bone.map][1] = min(limitDict[bone.bone.map][1], euler.y) + limitDict[bone.bone.map][2] = min(limitDict[bone.bone.map][2], euler.z) + limitDict[bone.bone.map][3] = max(limitDict[bone.bone.map][3], euler.x) + limitDict[bone.bone.map][4] = max(limitDict[bone.bone.map][4], euler.y) + limitDict[bone.bone.map][5] = max(limitDict[bone.bone.map][5], euler.z) + for bone in enduser_obj.pose.bones: + existingConstraint = [constraint for constraint in bone.constraints if constraint.name == "DOF Limitation"] + if existingConstraint: + bone.constraints.remove(existingConstraint[0]) + end_bones = [bone for bone in enduser_obj.pose.bones if bone.name in limitDict.keys()] + for bone in end_bones: + #~ if not bone.is_in_ik_chain: + newCons = bone.constraints.new("LIMIT_ROTATION") + newCons.name = "DOF Limitation" + newCons.owner_space = "LOCAL" + newCons.min_x, newCons.min_y, newCons.min_z, newCons.max_x, newCons.max_y, newCons.max_z = limitDict[bone.name] + newCons.use_limit_x = True + newCons.use_limit_y = True + newCons.use_limit_z = True + #~ else: + #~ bone.ik_min_x, bone.ik_min_y, bone.ik_min_z, bone.ik_max_x, bone.ik_max_y, bone.ik_max_z = limitDict[bone.name] + #~ bone.use_ik_limit_x = True + #~ bone.use_ik_limit_y = True + #~ bone.use_ik_limit_z= True + #~ bone.ik_stiffness_x = 1/((limitDict[bone.name][3] - limitDict[bone.name][0])/(2*pi))) + #~ bone.ik_stiffness_y = 1/((limitDict[bone.name][4] - limitDict[bone.name][1])/(2*pi))) + #~ bone.ik_stiffness_z = 1/((limitDict[bone.name][5] - limitDict[bone.name][2])/(2*pi))) + + context.scene.frame_set(c_frame) + + +def limit_dof_toggle_off(context, enduser_obj): + for bone in enduser_obj.pose.bones: + existingConstraint = [constraint for constraint in bone.constraints if constraint.name == "DOF Limitation"] + if existingConstraint: + bone.constraints.remove(existingConstraint[0]) -- cgit v1.2.3 From 0031950a746d6a1b632e6c57359432803e8871c9 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Wed, 3 Aug 2011 18:17:33 +0000 Subject: Fixed issue with IK toggle buttons and added operators for the new limit rotation functions --- release/scripts/startup/ui_mocap.py | 53 ++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 12 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index f31b580411a..ac063a3a0cc 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -52,11 +52,11 @@ class MocapConstraint(bpy.types.PropertyGroup): description="Other Constrained Bone (optional, depends on type)", update=setConstraint) s_frame = bpy.props.IntProperty(name="S", - default=bpy.context.scene.frame_start, + default=0, description="Start frame of Fix", update=setConstraint) e_frame = bpy.props.IntProperty(name="E", - default=bpy.context.scene.frame_end, + default=100, description="End frame of Fix", update=setConstraint) smooth_in = bpy.props.IntProperty(name="In", @@ -125,24 +125,33 @@ def toggleIKBone(self, context): if hasIKConstraint(parent_bone): break deformer_children = [child for child in parent_bone.children if child.bone.use_deform] - if len(deformer_children) > 1: - break + #~ if len(deformer_children) > 1: + #~ break ik.chain_count = chainLen for bone in self.parent_recursive: if bone.is_in_ik_chain: bone.IKRetarget = True else: print(self.name + " IK toggled OFF!") - cnstrn_bone = False + cnstrn_bones = [] + newChainLength = [] if hasIKConstraint(self): - cnstrn_bone = self + cnstrn_bones = [self] elif self.is_in_ik_chain: - cnstrn_bone = [child for child in self.children_recursive if hasIKConstraint(child)][0] - if cnstrn_bone: + cnstrn_bones = [child for child in self.children_recursive if hasIKConstraint(child)] + for cnstrn_bone in cnstrn_bones: + newChainLength.append(cnstrn_bone.parent_recursive.index(self) + 1) + if cnstrn_bones: # remove constraint, and update IK retarget for all parents of cnstrn_bone up to chain_len - ik = [constraint for constraint in cnstrn_bone.constraints if constraint.type == "IK"][0] - cnstrn_bone.constraints.remove(ik) - cnstrn_bone.IKRetarget = False + for i, cnstrn_bone in enumerate(cnstrn_bones): + print(cnstrn_bone.name) + if newChainLength: + ik = hasIKConstraint(cnstrn_bone) + ik.chain_count = newChainLength[i] + else: + ik = hasIKConstraint(cnstrn_bone) + cnstrn_bone.constraints.remove(ik) + cnstrn_bone.IKRetarget = False for bone in cnstrn_bone.parent_recursive: if not bone.is_in_ik_chain: bone.IKRetarget = False @@ -198,6 +207,7 @@ class MocapPanel(bpy.types.Panel): row2 = self.layout.row(align=True) row2.operator("mocap.looper", text='Loop animation') row2.operator("mocap.limitdof", text='Constrain Rig') + row2.operator("mocap.removelimitdof", text='Unconstrain Rig') self.layout.label("Retargeting") enduser_obj = bpy.context.active_object performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj] @@ -414,11 +424,13 @@ class OBJECT_OT_DenoiseButton(bpy.types.Operator): class OBJECT_OT_LimitDOFButton(bpy.types.Operator): - '''UNIMPLEMENTED: Create limit constraints on the active armature from the selected armature's animation's range of motion''' + '''Create limit constraints on the active armature from the selected armature's animation's range of motion''' bl_idname = "mocap.limitdof" bl_label = "Analyzes animations Max/Min DOF and adds hard/soft constraints" def execute(self, context): + performer_obj = [obj for obj in context.selected_objects if obj != context.active_object][0] + mocap_tools.limit_dof(context, performer_obj, context.active_object) return {"FINISHED"} @classmethod @@ -432,6 +444,23 @@ class OBJECT_OT_LimitDOFButton(bpy.types.Operator): return False +class OBJECT_OT_RemoveLimitDOFButton(bpy.types.Operator): + '''Removes previously created limit constraints on the active armature''' + bl_idname = "mocap.removelimitdof" + bl_label = "Removes previously created limit constraints on the active armature" + + def execute(self, context): + mocap_tools.limit_dof_toggle_off(context, context.active_object) + return {"FINISHED"} + + @classmethod + def poll(cls, context): + activeIsArmature = False + if context.active_object: + activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) + return activeIsArmature + + class OBJECT_OT_RotateFixArmature(bpy.types.Operator): '''Realign the active armature's axis system to match Blender (Commonly needed after bvh import)''' bl_idname = "mocap.rotate_fix" -- cgit v1.2.3 From ecd4b869828bc5ed7e3d00ac8dc9e93832f2c156 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Wed, 3 Aug 2011 22:26:59 +0000 Subject: Initial coding of path editing operator. Still needs some work, but all the basic functionality is there. Select a path and the stride bone (as active) and it will reparameterize the path to propel the armature forward in the same magnitude of the original --- release/scripts/modules/mocap_tools.py | 61 +++++++++++++++++++++++++++++++--- release/scripts/startup/ui_mocap.py | 33 +++++++++++++++++- 2 files changed, 89 insertions(+), 5 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index 703db4477ba..20163cd46b8 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -81,6 +81,9 @@ class NdVector: def y(self): return self.vec[1] + def resize_2d(self): + return Vector((self.x, self.y)) + length = property(vecLength) lengthSq = property(vecLengthSq) x = property(x) @@ -322,7 +325,10 @@ def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): return 0, None for pt in data_pts[s:e + 1]: bezVal = bezierEval(bez, pt.u) - tmpError = (pt.co - bezVal).length / pt.co.length + normalize_error = pt.co.length + if normalize_error == 0: + normalize_error = 1 + tmpError = (pt.co - bezVal).length / normalize_error if tmpError >= maxError: maxError = tmpError maxErrorPt = pt.index @@ -471,10 +477,8 @@ def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): #(e.g. a bone's x,y,z rotation) -def fcurves_simplify(sel_opt="all", error=0.002, group_mode=True): +def fcurves_simplify(context, obj, sel_opt="all", error=0.002, group_mode=True): # main vars - context = bpy.context - obj = context.active_object fcurves = obj.animation_data.action.fcurves if sel_opt == "sel": @@ -706,3 +710,52 @@ def limit_dof_toggle_off(context, enduser_obj): existingConstraint = [constraint for constraint in bone.constraints if constraint.name == "DOF Limitation"] if existingConstraint: bone.constraints.remove(existingConstraint[0]) + + +def path_editing(context, stride_obj, path): + y_fcurve = [fcurve for fcurve in stride_obj.animation_data.action.fcurves if fcurve.data_path == "location"][1] + s, e = context.scene.frame_start, context.scene.frame_end # y_fcurve.range() + s = int(s) + e = int(e) + y_s = y_fcurve.evaluate(s) + y_e = y_fcurve.evaluate(e) + direction = (y_e - y_s) / abs(y_e - y_s) + existing_cons = [constraint for constraint in stride_obj.constraints if constraint.type == "FOLLOW_PATH"] + for cons in existing_cons: + stride_obj.constraints.remove(cons) + path_cons = stride_obj.constraints.new("FOLLOW_PATH") + if direction < 0: + path_cons.forward_axis = "TRACK_NEGATIVE_Y" + else: + path_cons.forward_axis = "FORWARD_Y" + path_cons.target = path + path_cons.use_curve_follow = True + path.data.path_duration = e - s + try: + path.data.animation_data.action.fcurves + except AttributeError: + path.data.keyframe_insert("eval_time", frame=0) + eval_time_fcurve = [fcurve for fcurve in path.data.animation_data.action.fcurves if fcurve.data_path == "eval_time"] + eval_time_fcurve = eval_time_fcurve[0] + totalLength = 0 + parameterization = {} + print("evaluating curve") + for t in range(s, e - 1): + if s == t: + chordLength = 0 + else: + chordLength = (y_fcurve.evaluate(t) - y_fcurve.evaluate(t + 1)) + totalLength += chordLength + parameterization[t] = totalLength + for t in range(s + 1, e - 1): + if totalLength == 0: + print("no forward motion") + parameterization[t] /= totalLength + parameterization[t] *= e - s + parameterization[e] = e - s + for t in parameterization.keys(): + eval_time_fcurve.keyframe_points.insert(frame=t, value=parameterization[t]) + error = 0.01 + reparaError = error * 32 + maxIterations = 16 + print("finished path editing") diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index ac063a3a0cc..03d173df7a6 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -304,6 +304,18 @@ class MocapConstraintsPanel(bpy.types.Panel): layout.separator() +class ExtraToolsPanel(bpy.types.Panel): + # Motion capture retargeting panel + bl_label = "Extra Mocap Tools" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "object" + + def draw(self, context): + layout = self.layout + layout.operator('mocap.pathediting', text="Follow Path") + + class OBJECT_OT_RetargetButton(bpy.types.Operator): '''Retarget animation from selected armature to active armature ''' bl_idname = "mocap.retarget" @@ -383,7 +395,7 @@ class OBJECT_OT_ConvertSamplesButton(bpy.types.Operator): bl_label = "Converts samples / simplifies keyframes to beziers" def execute(self, context): - mocap_tools.fcurves_simplify() + mocap_tools.fcurves_simplify(context, context.active_object) return {"FINISHED"} @classmethod @@ -598,6 +610,25 @@ class OBJECT_OT_GuessHierachyMapping(bpy.types.Operator): return False +class OBJECT_OT_PathEditing(bpy.types.Operator): + '''Sets active object (stride object) to follow the selected curve''' + bl_idname = "mocap.pathediting" + bl_label = "Sets active object (stride object) to follow the selected curve" + + def execute(self, context): + path = [obj for obj in context.selected_objects if obj != context.active_object][0] + mocap_tools.path_editing(context, context.active_object, path) + return {"FINISHED"} + + @classmethod + def poll(cls, context): + if context.active_object: + selected_objs = [obj for obj in context.selected_objects if obj != context.active_object] + return selected_objs + else: + return False + + def register(): bpy.utils.register_module(__name__) -- cgit v1.2.3 From b5e55ff44b7b9cb58c8fc92f7dd66a4443ecea5b Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Fri, 5 Aug 2011 08:40:06 +0000 Subject: Small fix to Path Editing - now mute's original forward motion curve --- release/scripts/modules/mocap_tools.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index 20163cd46b8..17f9e590d10 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -755,7 +755,5 @@ def path_editing(context, stride_obj, path): parameterization[e] = e - s for t in parameterization.keys(): eval_time_fcurve.keyframe_points.insert(frame=t, value=parameterization[t]) - error = 0.01 - reparaError = error * 32 - maxIterations = 16 + y_fcurve.mute = True print("finished path editing") -- cgit v1.2.3 From 63c7bacc7b56dcca559d88a79190933c98017f36 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Fri, 5 Aug 2011 08:41:16 +0000 Subject: Updated Vector/Matrix multiplication to new order as required by mathutils --- release/scripts/modules/retarget.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index bec7b8aaa3e..629e363b918 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -285,7 +285,7 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame scene.frame_set(t) #calculate the new position, by dividing by the found ratio between performer and enduser newTranslation = (tailLoc(perf_bones[perfRoot]) / avg) - stride_bone.location = (newTranslation - initialPos) * enduser_obj_mat + stride_bone.location = enduser_obj_mat * (newTranslation - initialPos) stride_bone.keyframe_insert("location") return stride_bone -- cgit v1.2.3 From 9a9330d88c83b4c7ea76cd46a1fecd0c8e4e349e Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Fri, 5 Aug 2011 08:44:16 +0000 Subject: Post Retarget fixes - added an Update Constraints button, that recalculates all fixes. Useful for when the user makes some external change to the animation --- release/scripts/modules/mocap_constraints.py | 7 +++++++ release/scripts/startup/ui_mocap.py | 22 +++++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py index 8fd42d17392..75afbe62231 100644 --- a/release/scripts/modules/mocap_constraints.py +++ b/release/scripts/modules/mocap_constraints.py @@ -419,3 +419,10 @@ def unbakeConstraints(context): if ik_con: ik_con.mute = False m_constraint.active = True + + +def updateConstraints(obj, context): + fixes = obj.data.mocap_constraints + for fix in fixes: + fix.active = False + fix.active = True diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 03d173df7a6..8ef4c1e7591 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -264,9 +264,10 @@ class MocapConstraintsPanel(bpy.types.Panel): enduser_obj = context.active_object enduser_arm = enduser_obj.data layout.operator_menu_enum("mocap.addmocapfix", "type") + layout.operator("mocap.updateconstraints", text='Update Fixes') bakeRow = layout.row() - bakeRow.operator("mocap.bakeconstraints") - bakeRow.operator("mocap.unbakeconstraints") + bakeRow.operator("mocap.bakeconstraints", text='Bake Fixes') + bakeRow.operator("mocap.unbakeconstraints", text='Unbake Fixes') layout.separator() for i, m_constraint in enumerate(enduser_arm.mocap_constraints): box = layout.box() @@ -588,6 +589,21 @@ class OBJECT_OT_UnbakeMocapConstraints(bpy.types.Operator): return isinstance(context.active_object.data, bpy.types.Armature) +class OBJECT_OT_UpdateMocapConstraints(bpy.types.Operator): + '''Updates all post-retarget fixes - needed after changes to armature object or pose''' + bl_idname = "mocap.updateconstraints" + bl_label = "Updates all fixes to target armature - neccesary to take under consideration changes to armature object or pose" + + def execute(self, context): + updateConstraints(context.active_object, context) + return {"FINISHED"} + + @classmethod + def poll(cls, context): + if context.active_object: + return isinstance(context.active_object.data, bpy.types.Armature) + + class OBJECT_OT_GuessHierachyMapping(bpy.types.Operator): '''Attemps to auto figure out hierarchy mapping''' bl_idname = "mocap.guessmapping" @@ -623,7 +639,7 @@ class OBJECT_OT_PathEditing(bpy.types.Operator): @classmethod def poll(cls, context): if context.active_object: - selected_objs = [obj for obj in context.selected_objects if obj != context.active_object] + selected_objs = [obj for obj in context.selected_objects if obj != context.active_object and isinstance(obj.data, bpy.types.Curve)] return selected_objs else: return False -- cgit v1.2.3 From c334bf69a7282254bb80bb2896bd8716930a4adf Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Sat, 6 Aug 2011 17:57:20 +0000 Subject: 3D Audio GSoC: Mixdown functionality. * Mixdown possible via libsndfile and ffmpeg! * Fixed some ffmpeg deprecation warnings * Mixdown UI only shows working Container, Codec and Format combinations! * Minor bugs and warnings fixed --- release/scripts/startup/bl_ui/properties_scene.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py index a9310fcc532..c3784b9f692 100644 --- a/release/scripts/startup/bl_ui/properties_scene.py +++ b/release/scripts/startup/bl_ui/properties_scene.py @@ -70,6 +70,8 @@ class SCENE_PT_audio(SceneButtonsPanel, bpy.types.Panel): col.prop(rd, "ffmpeg_audio_channels", text="") col.prop(rd, "ffmpeg_audio_mixrate", text="Rate") + layout.operator("sound.mixdown") + class SCENE_PT_unit(SceneButtonsPanel, bpy.types.Panel): bl_label = "Units" -- cgit v1.2.3 From 022e815fbd6d81f9b1baa177cce1abf2f42bcb21 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sun, 7 Aug 2011 12:27:20 +0000 Subject: Sound clip NLA Strips for Nexyon These are basically just for specifying when a speaker should fire off it's soundclip, and as such, many NLA operations are irrelevant for it. They can only be specified on object-level for speaker objects. I've still got some UI tweaks I'll need to work on in order for these to be able to be added even when the speaker doesn't have any NLA tracks yet. (EDIT: while typing this, I had an idea for how to do this, but that'll be for next commit). In the mean time, you'll need to add a single keyframe for the object, snowflake that action and delete the NLA strip before you can start editing. --- release/scripts/startup/bl_ui/space_nla.py | 1 + 1 file changed, 1 insertion(+) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py index 78489db6317..b6c2d078960 100644 --- a/release/scripts/startup/bl_ui/space_nla.py +++ b/release/scripts/startup/bl_ui/space_nla.py @@ -173,6 +173,7 @@ class NLA_MT_add(bpy.types.Menu): layout.column() layout.operator("nla.actionclip_add") layout.operator("nla.transition_add") + layout.operator("nla.soundclip_add") layout.separator() layout.operator("nla.meta_add") -- cgit v1.2.3 From 60eec89cda50360c8fc68f9d3d6dc18e5c6633b1 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Mon, 8 Aug 2011 11:09:56 +0000 Subject: Created property systems for multiple retargets on a single armature, for this type of use and animation stitching. Also contains some placeholder UI and code for animation stitching. --- release/scripts/modules/mocap_constraints.py | 8 ++-- release/scripts/modules/mocap_tools.py | 8 ++++ release/scripts/modules/retarget.py | 68 ++++++++++++++++++--------- release/scripts/startup/ui_mocap.py | 69 ++++++++++++++++++++++++++-- 4 files changed, 126 insertions(+), 27 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py index 75afbe62231..63e46f99349 100644 --- a/release/scripts/modules/mocap_constraints.py +++ b/release/scripts/modules/mocap_constraints.py @@ -59,7 +59,7 @@ def addNewConstraint(m_constraint, cons_obj): c_type = "LIMIT_LOCATION" #create and store the new constraint within m_constraint real_constraint = cons_obj.constraints.new(c_type) - real_constraint.name = "Mocap fix " + str(len(cons_obj.constraints)) + real_constraint.name = "Auto fixes " + str(len(cons_obj.constraints)) m_constraint.real_constraint_bone = consObjToBone(cons_obj) m_constraint.real_constraint = real_constraint.name #set the rest of the constraint properties @@ -364,7 +364,8 @@ def bakeAllConstraints(obj, s_frame, e_frame, bones): simpleBake += [end_bone] for bone in selectedBones: bone.bone.select = True - constraintTrack = obj.animation_data.nla_tracks["Mocap fixes"] + tracks = [track for track in obj.data.mocapNLATracks if track.active][0] + constraintTrack = obj.animation_data.nla_tracks[tracks.auto_fix_track] constraintStrip = constraintTrack.strips[0] constraintStrip.action_frame_start = s_frame constraintStrip.action_frame_end = e_frame @@ -403,7 +404,8 @@ def unbakeConstraints(context): obj = context.active_object bones = obj.pose.bones scene = bpy.context.scene - constraintTrack = obj.animation_data.nla_tracks["Mocap fixes"] + tracks = obj.data.mocapNLATracks[obj.animation_data.action] + constraintTrack = obj.animation_data.nla_tracks[tracks.auto_fix_track] constraintStrip = constraintTrack.strips[0] action = constraintStrip.action # delete the fcurves on the strip diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index 17f9e590d10..fa307a36a57 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -757,3 +757,11 @@ def path_editing(context, stride_obj, path): eval_time_fcurve.keyframe_points.insert(frame=t, value=parameterization[t]) y_fcurve.mute = True print("finished path editing") + + +def anim_stitch(context, enduser_obj): + stitch_settings = enduser_obj.data.stitch_settings + action_1 = stitch_settings.first_action + action_2 = stitch_settings.second_action + TrackNamesA = enduser_obj.data.mocapNLATracks[action_1] + TrackNamesB = enduser_obj.data.mocapNLATracks[action_2] diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 629e363b918..b3c386e6c4d 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -272,21 +272,31 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame if endV.length != 0: linearAvg.append(hipV.length / endV.length) - bpy.ops.object.add() - stride_bone = bpy.context.active_object - stride_bone.name = "stride_bone" - + action_name = performer_obj.animation_data.action.name + #if you have a parent, and that parent is a previously created stride bone + if enduser_obj.parent: + stride_action = bpy.data.actions.new("Stride Bone " + action_name) + stride_bone = enduser_obj.parent + stride_bone.animation_data.action = stride_action + else: + bpy.ops.object.add() + stride_bone = bpy.context.active_object + stride_bone.name = "stride_bone" + print(stride_bone) + stride_bone.location = Vector((0, 0, 0)) if linearAvg: #determine the average change in scale needed avg = sum(linearAvg) / len(linearAvg) scene.frame_set(s_frame) - initialPos = (tailLoc(perf_bones[perfRoot]) / avg) + initialPos = (tailLoc(perf_bones[perfRoot]) / avg) + stride_bone.location for t in range(s_frame, e_frame): scene.frame_set(t) #calculate the new position, by dividing by the found ratio between performer and enduser newTranslation = (tailLoc(perf_bones[perfRoot]) / avg) stride_bone.location = enduser_obj_mat * (newTranslation - initialPos) stride_bone.keyframe_insert("location") + stride_bone.animation_data.action.name = ("Stride Bone " + action_name) + return stride_bone @@ -299,7 +309,7 @@ def IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene): # set constraint target to corresponding empty if targetless, # if not, keyframe current target to corresponding empty perf_bone = pose_bone.bone.reverseMap[-1].name - orgLocTrg = originalLocationTarget(pose_bone) + orgLocTrg = originalLocationTarget(pose_bone, enduser_obj) if not ik_constraint.target: ik_constraint.target = orgLocTrg target = orgLocTrg @@ -322,6 +332,7 @@ def IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene): target.location = final_loc target.keyframe_insert("location") ik_constraint.mute = False + scene.frame_set(s_frame) def turnOffIK(enduser_obj): @@ -358,44 +369,59 @@ def restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, str empty = bpy.data.objects[pose_bone.name + "Org"] empty.parent = stride_bone performer_obj.matrix_world = perf_obj_mat - enduser_obj.matrix_world = enduser_obj_mat enduser_obj.parent = stride_bone + enduser_obj.matrix_world = enduser_obj_mat #create (or return if exists) the related IK empty to the bone -def originalLocationTarget(end_bone): +def originalLocationTarget(end_bone, enduser_obj): if not end_bone.name + "Org" in bpy.data.objects: bpy.ops.object.add() empty = bpy.context.active_object empty.name = end_bone.name + "Org" empty.empty_draw_size = 0.1 - #empty.parent = enduser_obj + empty.parent = enduser_obj empty = bpy.data.objects[end_bone.name + "Org"] return empty #create the specified NLA setup for base animation, constraints and tweak layer. -def NLASystemInitialize(enduser_obj, s_frame): +def NLASystemInitialize(enduser_obj, s_frame, name): anim_data = enduser_obj.animation_data + if not name in enduser_obj.data.mocapNLATracks: + NLATracks = enduser_obj.data.mocapNLATracks.add() + NLATracks.name = name + else: + NLATracks = enduser_obj.data.mocapNLATracks[name] + for track in enduser_obj.data.mocapNLATracks: + track.active = False mocapAction = anim_data.action - mocapAction.name = "Base Mocap" + mocapAction.name = "Base " + name anim_data.use_nla = True + for track in anim_data.nla_tracks: + anim_data.nla_tracks.remove(track) mocapTrack = anim_data.nla_tracks.new() - mocapTrack.name = "Base Mocap Track" - mocapStrip = mocapTrack.strips.new("Base Mocap", s_frame, mocapAction) + mocapTrack.name = "Base " + name + NLATracks.base_track = mocapTrack.name + mocapStrip = mocapTrack.strips.new("Base " + name, s_frame, mocapAction) constraintTrack = anim_data.nla_tracks.new() - constraintTrack.name = "Mocap fixes" - constraintAction = bpy.data.actions.new("Mocap fixes") - constraintStrip = constraintTrack.strips.new("Mocap fixes", s_frame, constraintAction) + constraintTrack.name = "Auto fixes " + name + NLATracks.auto_fix_track = constraintTrack.name + constraintAction = bpy.data.actions.new("Auto fixes " + name) + constraintStrip = constraintTrack.strips.new("Auto fixes " + name, s_frame, constraintAction) constraintStrip.extrapolation = "NOTHING" userTrack = anim_data.nla_tracks.new() - userTrack.name = "Mocap manual fix" - userAction = bpy.data.actions.new("Mocap manual fix") - userStrip = userTrack.strips.new("Mocap manual fix", s_frame, userAction) + userTrack.name = "Manual fixes " + name + NLATracks.manual_fix_track = userTrack.name + if enduser_obj.parent.animation_data: + NLATracks.stride_action = enduser_obj.parent.animation_data.action.name + userAction = bpy.data.actions.new("Manual fixes " + name) + userStrip = userTrack.strips.new("Manual fixes " + name, s_frame, userAction) userStrip.extrapolation = "HOLD" #userStrip.blend_type = "MULITPLY" - doesn't work due to work, will be activated soon anim_data.nla_tracks.active = constraintTrack - anim_data.action = constraintAction + NLATracks.active = True + #anim_data.action = constraintAction anim_data.action_extrapolation = "NOTHING" @@ -419,7 +445,7 @@ def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_name(name=inter_obj.name, extend=False) bpy.ops.object.delete() - NLASystemInitialize(enduser_obj, s_frame) + NLASystemInitialize(enduser_obj, s_frame, performer_obj.animation_data.action.name) print("retargeting done!") if __name__ == "__main__": diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 8ef4c1e7591..3d034b0047a 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -110,6 +110,35 @@ bpy.utils.register_class(MocapConstraint) bpy.types.Armature.mocap_constraints = bpy.props.CollectionProperty(type=MocapConstraint) + +class AnimationStitchSettings(bpy.types.PropertyGroup): + first_action = bpy.props.StringProperty(name="Action 1", + description="First action in stitch") + second_action = bpy.props.StringProperty(name="Action 2", + description="Second action in stitch") + blend_frame = bpy.props.IntProperty(name="Stitch frame", + description="Frame to locate stitch on") + blend_amount = bpy.props.IntProperty(name="Blend amount", + description="Size of blending transitiion, on both sides of the stitch", + default=10) + +bpy.utils.register_class(AnimationStitchSettings) + + +class MocapNLATracks(bpy.types.PropertyGroup): + name = bpy.props.StringProperty() + active = bpy.props.BoolProperty() + base_track = bpy.props.StringProperty() + auto_fix_track = bpy.props.StringProperty() + manual_fix_track = bpy.props.StringProperty() + stride_action = bpy.props.StringProperty() + +bpy.utils.register_class(MocapNLATracks) + +bpy.types.Armature.stitch_settings = bpy.props.PointerProperty(type=AnimationStitchSettings) + +bpy.types.Armature.mocapNLATracks = bpy.props.CollectionProperty(type=MocapNLATracks) + #Update function for IK functionality. Is called when IK prop checkboxes are toggled. @@ -246,6 +275,7 @@ class MocapPanel(bpy.types.Panel): mapRow = self.layout.row() mapRow.operator("mocap.savemapping", text='Save mapping') mapRow.operator("mocap.loadmapping", text='Load mapping') + self.layout.prop(data=performer_obj.animation_data.action, property='name', text='Action Name') self.layout.operator("mocap.retarget", text='RETARGET!') @@ -315,6 +345,16 @@ class ExtraToolsPanel(bpy.types.Panel): def draw(self, context): layout = self.layout layout.operator('mocap.pathediting', text="Follow Path") + layout.label("Animation Stitching") + activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) + if activeIsArmature: + enduser_arm = context.active_object.data + settings = enduser_arm.stitch_settings + layout.prop_search(settings, "first_action", enduser_arm, "mocapNLATracks") + layout.prop_search(settings, "second_action", enduser_arm, "mocapNLATracks") + layout.prop(settings, "blend_frame") + layout.prop(settings, "blend_amount") + layout.operator('mocap.animstitch', text="Stitch Animations") class OBJECT_OT_RetargetButton(bpy.types.Operator): @@ -323,15 +363,18 @@ class OBJECT_OT_RetargetButton(bpy.types.Operator): bl_label = "Retargets active action from Performer to Enduser" def execute(self, context): + scene = context.scene + s_frame = scene.frame_start + e_frame = scene.frame_end enduser_obj = context.active_object performer_obj = [obj for obj in context.selected_objects if obj != enduser_obj] if enduser_obj is None or len(performer_obj) != 1: print("Need active and selected armatures") else: performer_obj = performer_obj[0] - scene = context.scene - s_frame = scene.frame_start - e_frame = scene.frame_end + s_frame, e_frame = performer_obj.animation_data.action.frame_range + s_frame = int(s_frame) + e_frame = int(e_frame) retarget.totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame) return {"FINISHED"} @@ -645,6 +688,26 @@ class OBJECT_OT_PathEditing(bpy.types.Operator): return False +class OBJECT_OT_AnimationStitchingButton(bpy.types.Operator): + '''Stitches two defined animations into a single one via alignment of NLA Tracks''' + bl_idname = "mocap.animstitch" + bl_label = "Stitches two defined animations into a single one via alignment of NLA Tracks" + + def execute(self, context): + mocap_tools.anim_stitch(context, context.active_object) + return {"FINISHED"} + + @classmethod + def poll(cls, context): + activeIsArmature = False + if context.active_object: + activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) + if activeIsArmature: + stitch_settings = context.active_object.data.stitch_settings + return (stitch_settings.first_action and stitch_settings.second_action) + return False + + def register(): bpy.utils.register_module(__name__) -- cgit v1.2.3 From a672ab5e737202bede956a88357a96cf2728df15 Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Tue, 9 Aug 2011 14:10:32 +0000 Subject: 3D Audio GSoC: Improved waveform drawing in the sequencer. * Drawing the waveform of a sequencer strip is now independent from whether the sound is cached or not. * Improved drawing of the waveform in the sequencer (especially speed!). * Making it possible to vertically zoom more in the sequencer to better see the waveform for lipsync. * Fixed a bug which crashed blender on loading a sound file via ffmpeg. --- release/scripts/startup/bl_ui/space_sequencer.py | 1 + 1 file changed, 1 insertion(+) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 5320297dce2..19202088faf 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -638,6 +638,7 @@ class SEQUENCER_PT_sound(SequencerButtonsPanel, bpy.types.Panel): row.prop(strip.sound, "use_memory_cache") + layout.prop(strip, "waveform") layout.prop(strip, "volume") layout.prop(strip, "attenuation") layout.prop(strip, "pitch") -- cgit v1.2.3 From 0207d9ce275c7206fcf3abf9ba056ca18e0f3a87 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 9 Aug 2011 19:59:01 +0000 Subject: style change, harmless changes while looking into bug [#28196] --- .../startup/bl_operators/uvcalc_lightmap.py | 64 +++++++++++++++++----- 1 file changed, 50 insertions(+), 14 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py index 2f1acf0a5dc..d2371b0316a 100644 --- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py +++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py @@ -23,7 +23,15 @@ import mathutils class prettyface(object): - __slots__ = "uv", "width", "height", "children", "xoff", "yoff", "has_parent", "rot" + __slots__ = ("uv", + "width", + "height", + "children", + "xoff", + "yoff", + "has_parent", + "rot", + ) def __init__(self, data): self.has_parent = False @@ -263,10 +271,9 @@ def lightmap_uvpack(meshes, del trylens def trilensdiff(t1, t2): - return\ - abs(t1[1][t1[2][0]] - t2[1][t2[2][0]]) + \ - abs(t1[1][t1[2][1]] - t2[1][t2[2][1]]) + \ - abs(t1[1][t1[2][2]] - t2[1][t2[2][2]]) + return (abs(t1[1][t1[2][0]] - t2[1][t2[2][0]]) + + abs(t1[1][t1[2][1]] - t2[1][t2[2][1]]) + + abs(t1[1][t1[2][2]] - t2[1][t2[2][2]])) while tri_lengths: tri1 = tri_lengths.pop() @@ -543,22 +550,51 @@ class LightMapPack(bpy.types.Operator): bl_options = {'REGISTER', 'UNDO'} PREF_CONTEXT = bpy.props.EnumProperty( + name="Selection", + description="", items=(("SEL_FACES", "Selected Faces", "Space all UVs evently"), ("ALL_FACES", "All Faces", "Average space UVs edge length of each loop"), ("ALL_OBJECTS", "Selected Mesh Object", "Average space UVs edge length of each loop") ), - name="Selection", - description="") + ) # Image & UVs... - PREF_PACK_IN_ONE = BoolProperty(name="Share Tex Space", default=True, description="Objects Share texture space, map all objects into 1 uvmap") - PREF_NEW_UVLAYER = BoolProperty(name="New UV Layer", default=False, description="Create a new UV layer for every mesh packed") - PREF_APPLY_IMAGE = BoolProperty(name="New Image", default=False, description="Assign new images for every mesh (only one if shared tex space enabled)") - PREF_IMG_PX_SIZE = IntProperty(name="Image Size", min=64, max=5000, default=512, description="Width and Height for the new image") - + PREF_PACK_IN_ONE = BoolProperty( + name="Share Tex Space", + description=("Objects Share texture space, map all objects " + "into 1 uvmap"), + default=True, + ) + PREF_NEW_UVLAYER = BoolProperty( + name="New UV Layer", + description="Create a new UV layer for every mesh packed", + default=False, + ) + PREF_APPLY_IMAGE = BoolProperty( + name="New Image", + description=("Assign new images for every mesh (only one if " + "shared tex space enabled)"), + default=False, + ) + PREF_IMG_PX_SIZE = IntProperty( + name="Image Size", + description="Width and Height for the new image", + min=64, max=5000, + default=512, + ) # UV Packing... - PREF_BOX_DIV = IntProperty(name="Pack Quality", min=1, max=48, default=12, description="Pre Packing before the complex boxpack") - PREF_MARGIN_DIV = FloatProperty(name="Margin", min=0.001, max=1.0, default=0.1, description="Size of the margin as a division of the UV") + PREF_BOX_DIV = IntProperty( + name="Pack Quality", + description="Pre Packing before the complex boxpack", + min=1, max=48, + default=12, + ) + PREF_MARGIN_DIV = FloatProperty( + name="Margin", + description="Size of the margin as a division of the UV", + min=0.001, max=1.0, + default=0.1, + ) def execute(self, context): kwargs = self.as_keywords() -- cgit v1.2.3 From 036077ebc6c70a50932d5e0fd9380580a38a4bc7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 10 Aug 2011 09:16:35 +0000 Subject: fix for error in template --- release/scripts/templates/operator_modal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/templates/operator_modal.py b/release/scripts/templates/operator_modal.py index ed98c2cf50e..a428b097f82 100644 --- a/release/scripts/templates/operator_modal.py +++ b/release/scripts/templates/operator_modal.py @@ -47,4 +47,4 @@ if __name__ == "__main__": register() # test call - bpy.ops.object.modal_operator() + bpy.ops.object.modal_operator('INVOKE_DEFAULT') -- cgit v1.2.3 From 3758f125fc661ac6b85b1fc711f5ea31d799e85b Mon Sep 17 00:00:00 2001 From: Nathan Letwory Date: Wed, 10 Aug 2011 09:30:45 +0000 Subject: Fix for incorrect parameter amount. --- release/scripts/templates/operator_modal_timer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/templates/operator_modal_timer.py b/release/scripts/templates/operator_modal_timer.py index d2267191cf5..ec47390da81 100644 --- a/release/scripts/templates/operator_modal_timer.py +++ b/release/scripts/templates/operator_modal_timer.py @@ -10,7 +10,7 @@ class ModalTimerOperator(bpy.types.Operator): def modal(self, context, event): if event.type == 'ESC': - return self.cancel() + return self.cancel(context) if event.type == 'TIMER': # change theme color, silly! -- cgit v1.2.3 From e8471be5f225dd692e20e5fb841e33a2480c2bec Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Wed, 10 Aug 2011 16:03:45 +0000 Subject: 2.59 Splash screen by tomket7. Congratulations! MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Chosen by the jury Ben Simonds, Reynante Martinez and Hjalti Hjálmarsson. --- release/datafiles/splash.png | Bin 201866 -> 204738 bytes 1 file changed, 0 insertions(+), 0 deletions(-) (limited to 'release') diff --git a/release/datafiles/splash.png b/release/datafiles/splash.png index d6ccdb5b733..79339095b07 100644 Binary files a/release/datafiles/splash.png and b/release/datafiles/splash.png differ -- cgit v1.2.3 From 8afad10f986f60e5ccfaed2798067ddcea9b5fcf Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Wed, 10 Aug 2011 18:40:14 +0000 Subject: Continued changes to storing of retargeted animation data, making it possible to easily switch between all retargeted clips, and stitch them with the future operator --- release/scripts/modules/mocap_constraints.py | 12 ++++-- release/scripts/modules/retarget.py | 64 ++++++++++++++++++++-------- release/scripts/startup/ui_mocap.py | 5 ++- 3 files changed, 57 insertions(+), 24 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py index 63e46f99349..540e8fa06db 100644 --- a/release/scripts/modules/mocap_constraints.py +++ b/release/scripts/modules/mocap_constraints.py @@ -186,6 +186,8 @@ def setConstraint(m_constraint, context): bone = bones[m_constraint.constrained_bone] cons_obj = getConsObj(bone) real_constraint = cons_obj.constraints[m_constraint.real_constraint] + NLATracks = obj.data.mocapNLATracks[obj.data.active_mocap] + obj.animation_data.action = bpy.data.actions[NLATracks.auto_fix_track] #frame changing section setConstraintFraming(m_constraint, context) @@ -364,8 +366,9 @@ def bakeAllConstraints(obj, s_frame, e_frame, bones): simpleBake += [end_bone] for bone in selectedBones: bone.bone.select = True - tracks = [track for track in obj.data.mocapNLATracks if track.active][0] - constraintTrack = obj.animation_data.nla_tracks[tracks.auto_fix_track] + NLATracks = obj.data.mocapNLATracks[obj.data.active_mocap] + obj.animation_data.action = bpy.data.actions[NLATracks.auto_fix_track] + constraintTrack = obj.animation_data.nla_tracks[NLATracks.auto_fix_track] constraintStrip = constraintTrack.strips[0] constraintStrip.action_frame_start = s_frame constraintStrip.action_frame_end = e_frame @@ -404,8 +407,9 @@ def unbakeConstraints(context): obj = context.active_object bones = obj.pose.bones scene = bpy.context.scene - tracks = obj.data.mocapNLATracks[obj.animation_data.action] - constraintTrack = obj.animation_data.nla_tracks[tracks.auto_fix_track] + NLATracks = obj.data.mocapNLATracks[obj.data.active_mocap] + obj.animation_data.action = bpy.data.actions[NLATracks.auto_fix_track] + constraintTrack = obj.animation_data.nla_tracks[NLATracks.auto_fix_track] constraintStrip = constraintTrack.strips[0] action = constraintStrip.action # delete the fcurves on the strip diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index b3c386e6c4d..a0d89ae6e8b 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -52,7 +52,6 @@ def createDictionary(perf_arm, end_arm): feetBones = [bone.name for bone in perf_arm.bones if bone.foot] return feetBones, root - def loadMapping(perf_arm, end_arm): for end_bone in end_arm.bones: @@ -273,8 +272,8 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame linearAvg.append(hipV.length / endV.length) action_name = performer_obj.animation_data.action.name - #if you have a parent, and that parent is a previously created stride bone - if enduser_obj.parent: + #is there a stride_bone? + if "stride_bone" in bpy.data.objects: stride_action = bpy.data.actions.new("Stride Bone " + action_name) stride_bone = enduser_obj.parent stride_bone.animation_data.action = stride_action @@ -386,17 +385,17 @@ def originalLocationTarget(end_bone, enduser_obj): #create the specified NLA setup for base animation, constraints and tweak layer. -def NLASystemInitialize(enduser_obj, s_frame, name): +def NLASystemInitialize(enduser_arm, context):#enduser_obj, name): + enduser_obj = context.active_object + NLATracks = enduser_arm.mocapNLATracks[enduser_obj.data.active_mocap] + name = NLATracks.name anim_data = enduser_obj.animation_data - if not name in enduser_obj.data.mocapNLATracks: - NLATracks = enduser_obj.data.mocapNLATracks.add() - NLATracks.name = name + s_frame = 0 + print(name) + if ("Base " + name) in bpy.data.actions: + mocapAction = bpy.data.actions[("Base " + name)] else: - NLATracks = enduser_obj.data.mocapNLATracks[name] - for track in enduser_obj.data.mocapNLATracks: - track.active = False - mocapAction = anim_data.action - mocapAction.name = "Base " + name + print("That retargeted anim has no base action") anim_data.use_nla = True for track in anim_data.nla_tracks: anim_data.nla_tracks.remove(track) @@ -407,28 +406,46 @@ def NLASystemInitialize(enduser_obj, s_frame, name): constraintTrack = anim_data.nla_tracks.new() constraintTrack.name = "Auto fixes " + name NLATracks.auto_fix_track = constraintTrack.name - constraintAction = bpy.data.actions.new("Auto fixes " + name) + if ("Auto fixes " + name) in bpy.data.actions: + constraintAction = bpy.data.actions[("Auto fixes " + name)] + else: + constraintAction = bpy.data.actions.new("Auto fixes " + name) constraintStrip = constraintTrack.strips.new("Auto fixes " + name, s_frame, constraintAction) constraintStrip.extrapolation = "NOTHING" userTrack = anim_data.nla_tracks.new() userTrack.name = "Manual fixes " + name NLATracks.manual_fix_track = userTrack.name - if enduser_obj.parent.animation_data: - NLATracks.stride_action = enduser_obj.parent.animation_data.action.name - userAction = bpy.data.actions.new("Manual fixes " + name) + if ("Manual fixes " + name) in bpy.data.actions: + userAction = bpy.data.actions[("Manual fixes " + name)] + else: + userAction = bpy.data.actions.new("Manual fixes " + name) userStrip = userTrack.strips.new("Manual fixes " + name, s_frame, userAction) userStrip.extrapolation = "HOLD" #userStrip.blend_type = "MULITPLY" - doesn't work due to work, will be activated soon anim_data.nla_tracks.active = constraintTrack - NLATracks.active = True #anim_data.action = constraintAction anim_data.action_extrapolation = "NOTHING" + #set the stride_bone's action + if "stride_bone" in bpy.data.objects: + stride_bone = bpy.data.objects["stride_bone"] + if NLATracks.stride_action: + stride_bone.animation_data.action = bpy.data.actions[NLATracks.stride_action] + else: + NLATracks.stride_action = stride_bone.animation_data.action.name + anim_data.action = None #Main function that runs the retargeting sequence. def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): perf_arm = performer_obj.data end_arm = enduser_obj.data + + try: + enduser_obj.animation_data.action = bpy.data.actions.new("temp") + except: + print("no need to create new action") + + print("creating Dictionary") feetBones, root = createDictionary(perf_arm, end_arm) print("cleaning stuff up") @@ -437,7 +454,11 @@ def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): print("Creating intermediate armature (for first pass)") inter_obj = createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene) print("First pass: retargeting from intermediate to end user") + + retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene) + name = performer_obj.animation_data.action.name + enduser_obj.animation_data.action.name = "Base " + name print("Second pass: retargeting root translation and clean up") stride_bone = copyTranslation(performer_obj, enduser_obj, feetBones, root, s_frame, e_frame, scene, enduser_obj_mat) IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene) @@ -445,7 +466,14 @@ def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_name(name=inter_obj.name, extend=False) bpy.ops.object.delete() - NLASystemInitialize(enduser_obj, s_frame, performer_obj.animation_data.action.name) + bpy.ops.object.select_name(name=enduser_obj.name, extend=False) + + if not name in [tracks.name for tracks in end_arm.mocapNLATracks]: + NLATracks = end_arm.mocapNLATracks.add() + NLATracks.name = name + else: + NLATracks = end_arm.mocapNLATracks[name] + end_arm.active_mocap = name print("retargeting done!") if __name__ == "__main__": diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 3d034b0047a..01802893c4c 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -127,7 +127,6 @@ bpy.utils.register_class(AnimationStitchSettings) class MocapNLATracks(bpy.types.PropertyGroup): name = bpy.props.StringProperty() - active = bpy.props.BoolProperty() base_track = bpy.props.StringProperty() auto_fix_track = bpy.props.StringProperty() manual_fix_track = bpy.props.StringProperty() @@ -136,7 +135,7 @@ class MocapNLATracks(bpy.types.PropertyGroup): bpy.utils.register_class(MocapNLATracks) bpy.types.Armature.stitch_settings = bpy.props.PointerProperty(type=AnimationStitchSettings) - +bpy.types.Armature.active_mocap = bpy.props.StringProperty(update=retarget.NLASystemInitialize) bpy.types.Armature.mocapNLATracks = bpy.props.CollectionProperty(type=MocapNLATracks) #Update function for IK functionality. Is called when IK prop checkboxes are toggled. @@ -349,6 +348,8 @@ class ExtraToolsPanel(bpy.types.Panel): activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) if activeIsArmature: enduser_arm = context.active_object.data + layout.label("Retargeted Animations:") + layout.prop_search(enduser_arm, "active_mocap",enduser_arm, "mocapNLATracks") settings = enduser_arm.stitch_settings layout.prop_search(settings, "first_action", enduser_arm, "mocapNLATracks") layout.prop_search(settings, "second_action", enduser_arm, "mocapNLATracks") -- cgit v1.2.3 From b5d556d432044f8b6f74962b228024afa00bc882 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Wed, 10 Aug 2011 18:41:04 +0000 Subject: Initial programming of stitch animation operator. WIP --- release/scripts/modules/mocap_tools.py | 56 ++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'release') diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index fa307a36a57..0e296faf9f8 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -760,8 +760,64 @@ def path_editing(context, stride_obj, path): def anim_stitch(context, enduser_obj): + selected_bone = enduser_obj.pose.bones["Toes.L"] + second_offset = 5 + stitch_settings = enduser_obj.data.stitch_settings action_1 = stitch_settings.first_action action_2 = stitch_settings.second_action + scene = context.scene TrackNamesA = enduser_obj.data.mocapNLATracks[action_1] TrackNamesB = enduser_obj.data.mocapNLATracks[action_2] + enduser_obj.data.active_mocap = action_1 + anim_data = enduser_obj.animation_data + # add tracks for action 2 + mocapAction = bpy.data.actions[TrackNamesB.base_track] + mocapTrack = anim_data.nla_tracks.new() + mocapTrack.name = TrackNamesB.base_track + mocapStrip = mocapTrack.strips.new(TrackNamesB.base_track, stitch_settings.blend_frame, mocapAction) + mocapStrip.extrapolation = "HOLD_FORWARD" + mocapStrip.action_frame_start+=second_offset + mocapStrip.action_frame_end+=second_offset + constraintTrack = anim_data.nla_tracks.new() + constraintTrack.name = TrackNamesB.auto_fix_track + constraintAction = bpy.data.actions[TrackNamesB.auto_fix_track] + constraintStrip = constraintTrack.strips.new(TrackNamesB.auto_fix_track, stitch_settings.blend_frame, constraintAction) + constraintStrip.extrapolation = "HOLD_FORWARD" + userTrack = anim_data.nla_tracks.new() + userTrack.name = TrackNamesB.manual_fix_track + userAction = bpy.data.actions[TrackNamesB.manual_fix_track] + userStrip = userTrack.strips.new(TrackNamesB.manual_fix_track, stitch_settings.blend_frame, userAction) + userStrip.extrapolation = "HOLD_FORWARD" + #stride bone + if enduser_obj.parent: + if enduser_obj.parent.name == "stride_bone": + stride_bone = enduser_obj.parent + stride_anim_data = stride_bone.animation_data + stride_anim_data.use_nla = True + stride_anim_data.action = None + for track in stride_anim_data.nla_tracks: + stride_anim_data.nla_tracks.remove(track) + actionATrack = stride_anim_data.nla_tracks.new() + actionATrack.name = TrackNamesA.stride_action + actionAStrip = actionATrack.strips.new(TrackNamesA.stride_action, 0, bpy.data.actions[TrackNamesA.stride_action]) + actionAStrip.extrapolation = "NOTHING" + actionBTrack = stride_anim_data.nla_tracks.new() + actionBTrack.name = TrackNamesB.stride_action + actionBStrip = actionBTrack.strips.new(TrackNamesB.stride_action, stitch_settings.blend_frame, bpy.data.actions[TrackNamesB.stride_action]) + actionBStrip.extrapolation = "NOTHING" + #we need to change the stride_bone's action to add the offset + scene.frame_set(stitch_settings.blend_frame - 1) + desired_pos = selected_bone.tail * enduser_obj.matrix_world + scene.frame_set(stitch_settings.blend_frame) + actual_pos = selected_bone.tail * enduser_obj.matrix_world + offset = actual_pos - desired_pos + print(offset) + + for i,fcurve in enumerate([fcurve for fcurve in bpy.data.actions[TrackNamesB.stride_action].fcurves if fcurve.data_path=="location"]): + print(offset[i],i,fcurve.array_index) + for pt in fcurve.keyframe_points: + pt.co.y-=offset[i] + pt.handle_left.y-=offset[i] + pt.handle_right.y-=offset[i] + -- cgit v1.2.3 From 1eaeaf8cd8ea7ee923b6aeb26b031368ff6d679a Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Wed, 10 Aug 2011 20:36:52 +0000 Subject: Fix for previous commit, now a fake user flag is added when switching between retargeted animations, so they don't get lost on save --- release/scripts/modules/retarget.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index a0d89ae6e8b..9415553d4ff 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -275,6 +275,7 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame #is there a stride_bone? if "stride_bone" in bpy.data.objects: stride_action = bpy.data.actions.new("Stride Bone " + action_name) + stride_action.use_fake_user = True stride_bone = enduser_obj.parent stride_bone.animation_data.action = stride_action else: @@ -410,6 +411,7 @@ def NLASystemInitialize(enduser_arm, context):#enduser_obj, name): constraintAction = bpy.data.actions[("Auto fixes " + name)] else: constraintAction = bpy.data.actions.new("Auto fixes " + name) + constraintAction.use_fake_user = True constraintStrip = constraintTrack.strips.new("Auto fixes " + name, s_frame, constraintAction) constraintStrip.extrapolation = "NOTHING" userTrack = anim_data.nla_tracks.new() @@ -419,6 +421,7 @@ def NLASystemInitialize(enduser_arm, context):#enduser_obj, name): userAction = bpy.data.actions[("Manual fixes " + name)] else: userAction = bpy.data.actions.new("Manual fixes " + name) + userAction.use_fake_user = True userStrip = userTrack.strips.new("Manual fixes " + name, s_frame, userAction) userStrip.extrapolation = "HOLD" #userStrip.blend_type = "MULITPLY" - doesn't work due to work, will be activated soon @@ -432,6 +435,7 @@ def NLASystemInitialize(enduser_arm, context):#enduser_obj, name): stride_bone.animation_data.action = bpy.data.actions[NLATracks.stride_action] else: NLATracks.stride_action = stride_bone.animation_data.action.name + stride_bone.animation_data.action.use_fake_user = True anim_data.action = None @@ -442,6 +446,7 @@ def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): try: enduser_obj.animation_data.action = bpy.data.actions.new("temp") + enduser_obj.animation_data.action.use_fake_user = True except: print("no need to create new action") -- cgit v1.2.3 From fba1f50d0af22199f8d73aa6eb5e95e75c3f3d6a Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Wed, 10 Aug 2011 20:37:57 +0000 Subject: Mostly finished implementation of animation stitching, with lock bone functionality, allowing the user to choose a bone that maintains its position during the blend --- release/scripts/modules/mocap_tools.py | 22 ++++++++++++++-------- release/scripts/startup/ui_mocap.py | 8 ++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index 0e296faf9f8..b490d571dd8 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -760,12 +760,13 @@ def path_editing(context, stride_obj, path): def anim_stitch(context, enduser_obj): - selected_bone = enduser_obj.pose.bones["Toes.L"] - second_offset = 5 - stitch_settings = enduser_obj.data.stitch_settings action_1 = stitch_settings.first_action action_2 = stitch_settings.second_action + if stitch_settings.stick_bone!="": + selected_bone = enduser_obj.pose.bones[stitch_settings.stick_bone] + else: + selected_bone = enduser_obj.pose.bones[0] scene = context.scene TrackNamesA = enduser_obj.data.mocapNLATracks[action_1] TrackNamesB = enduser_obj.data.mocapNLATracks[action_2] @@ -777,18 +778,21 @@ def anim_stitch(context, enduser_obj): mocapTrack.name = TrackNamesB.base_track mocapStrip = mocapTrack.strips.new(TrackNamesB.base_track, stitch_settings.blend_frame, mocapAction) mocapStrip.extrapolation = "HOLD_FORWARD" - mocapStrip.action_frame_start+=second_offset - mocapStrip.action_frame_end+=second_offset + mocapStrip.blend_in = stitch_settings.blend_amount + mocapStrip.action_frame_start+=stitch_settings.second_offset + mocapStrip.action_frame_end+=stitch_settings.second_offset constraintTrack = anim_data.nla_tracks.new() constraintTrack.name = TrackNamesB.auto_fix_track constraintAction = bpy.data.actions[TrackNamesB.auto_fix_track] constraintStrip = constraintTrack.strips.new(TrackNamesB.auto_fix_track, stitch_settings.blend_frame, constraintAction) constraintStrip.extrapolation = "HOLD_FORWARD" + constraintStrip.blend_in = stitch_settings.blend_amount userTrack = anim_data.nla_tracks.new() userTrack.name = TrackNamesB.manual_fix_track userAction = bpy.data.actions[TrackNamesB.manual_fix_track] userStrip = userTrack.strips.new(TrackNamesB.manual_fix_track, stitch_settings.blend_frame, userAction) userStrip.extrapolation = "HOLD_FORWARD" + userStrip.blend_in = stitch_settings.blend_amount #stride bone if enduser_obj.parent: if enduser_obj.parent.name == "stride_bone": @@ -805,14 +809,16 @@ def anim_stitch(context, enduser_obj): actionBTrack = stride_anim_data.nla_tracks.new() actionBTrack.name = TrackNamesB.stride_action actionBStrip = actionBTrack.strips.new(TrackNamesB.stride_action, stitch_settings.blend_frame, bpy.data.actions[TrackNamesB.stride_action]) + actionBStrip.action_frame_start+=stitch_settings.second_offset + actionBStrip.action_frame_end+=stitch_settings.second_offset + actionBStrip.blend_in = stitch_settings.blend_amount actionBStrip.extrapolation = "NOTHING" #we need to change the stride_bone's action to add the offset scene.frame_set(stitch_settings.blend_frame - 1) - desired_pos = selected_bone.tail * enduser_obj.matrix_world + desired_pos = (selected_bone.matrix.to_translation() * enduser_obj.matrix_world) scene.frame_set(stitch_settings.blend_frame) - actual_pos = selected_bone.tail * enduser_obj.matrix_world + actual_pos = (selected_bone.matrix.to_translation() * enduser_obj.matrix_world) offset = actual_pos - desired_pos - print(offset) for i,fcurve in enumerate([fcurve for fcurve in bpy.data.actions[TrackNamesB.stride_action].fcurves if fcurve.data_path=="location"]): print(offset[i],i,fcurve.array_index) diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 01802893c4c..0788366547e 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -121,6 +121,12 @@ class AnimationStitchSettings(bpy.types.PropertyGroup): blend_amount = bpy.props.IntProperty(name="Blend amount", description="Size of blending transitiion, on both sides of the stitch", default=10) + second_offset = bpy.props.IntProperty(name="Second offset", + description="Frame offset for 2nd animation, where it should start", + default=10) + stick_bone = bpy.props.StringProperty(name="Stick Bone", + description="Bone to freeze during transition", + default="") bpy.utils.register_class(AnimationStitchSettings) @@ -355,6 +361,8 @@ class ExtraToolsPanel(bpy.types.Panel): layout.prop_search(settings, "second_action", enduser_arm, "mocapNLATracks") layout.prop(settings, "blend_frame") layout.prop(settings, "blend_amount") + layout.prop(settings, "second_offset") + layout.prop_search(settings, "stick_bone", context.active_object.pose, "bones") layout.operator('mocap.animstitch', text="Stitch Animations") -- cgit v1.2.3 From fee7337249342c3d5a332358883af9afe961f38d Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Thu, 11 Aug 2011 11:41:24 +0000 Subject: 3D Audio GSoC: Adding a mono flag to mixdown non-mono sounds for 3D audio. * Added mono sound loading. * Bugfix: AUD_COMPARE_SPECS usage was wrong. * Bugfix: JOS resampler = instead of ==. * Bugfix: Change of a sound should apply settings in AUD_SequencerHandle. * Bugfix: Memory leak when canceling open sound operator. --- release/scripts/startup/bl_ui/properties_data_speaker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/properties_data_speaker.py b/release/scripts/startup/bl_ui/properties_data_speaker.py index 45f2fa5d1f7..fe9f798af0c 100644 --- a/release/scripts/startup/bl_ui/properties_data_speaker.py +++ b/release/scripts/startup/bl_ui/properties_data_speaker.py @@ -63,7 +63,7 @@ class DATA_PT_speaker(DataButtonsPanel, bpy.types.Panel): split = layout.split(percentage=0.75) - split.template_ID(speaker, "sound", open="sound.open") + split.template_ID(speaker, "sound", open="sound.open_mono") split.prop(speaker, "muted") split = layout.split() -- cgit v1.2.3 From 87e9c0ffaa5f8f64ccdea5c2ce74dfbd0edf0e43 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Thu, 11 Aug 2011 13:47:49 +0000 Subject: Advanced Retargeting option: If the end user armature is complex, on the level of Sintel/Mancandy rigs, the user is requested to mark Advanced Retargeting, and constraints will be semi automatically configured to retarget the animation and then Retargeting will bake and remove these constraints --- release/scripts/modules/retarget.py | 89 ++++++++++++++++++++++++++++++++----- release/scripts/startup/ui_mocap.py | 51 ++++++++++++++++++++- 2 files changed, 127 insertions(+), 13 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 9415553d4ff..88a5c3a620a 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -21,6 +21,7 @@ import bpy from mathutils import * from math import radians, acos +from bl_operators import nla import cProfile @@ -264,6 +265,7 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame v = locDeriv[key][i] hipV = locDeriv[perfRoot][i] endV = locDeriv[perf_bones[key].bone.map][i] + print(v.length,) if (v.length < 0.1): #this is a plant frame. #lets see what the original hip delta is, and the corresponding @@ -284,6 +286,7 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame stride_bone.name = "stride_bone" print(stride_bone) stride_bone.location = Vector((0, 0, 0)) + print(linearAvg) if linearAvg: #determine the average change in scale needed avg = sum(linearAvg) / len(linearAvg) @@ -295,6 +298,8 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame newTranslation = (tailLoc(perf_bones[perfRoot]) / avg) stride_bone.location = enduser_obj_mat * (newTranslation - initialPos) stride_bone.keyframe_insert("location") + else: + stride_bone.keyframe_insert("location") stride_bone.animation_data.action.name = ("Stride Bone " + action_name) return stride_bone @@ -439,10 +444,66 @@ def NLASystemInitialize(enduser_arm, context):#enduser_obj, name): anim_data.action = None +def preAdvancedRetargeting(performer_obj, enduser_obj): + createDictionary(performer_obj.data, enduser_obj.data) + bones = enduser_obj.pose.bones + map_bones = [bone for bone in bones if bone.bone.reverseMap] + for bone in map_bones: + perf_bone = bone.bone.reverseMap[0].name + addLocalRot = False; + if bone.bone.use_connect or not bone.constraints: + locks = bone.lock_location + if not (locks[0] or locks[1] or locks[2]): + cons = bone.constraints.new('COPY_LOCATION') + cons.name = "retargetTemp" + cons.use_x = not locks[0] + cons.use_y = not locks[1] + cons.use_z = not locks[2] + cons.target = performer_obj + cons.subtarget = perf_bone + addLocalRot = True + + + cons2 = bone.constraints.new('COPY_ROTATION') + cons2.name = "retargetTemp" + locks = bone.lock_rotation + cons2.use_x = not locks[0] + cons2.use_y = not locks[1] + cons2.use_z = not locks[2] + cons2.target = performer_obj + cons2.subtarget = perf_bone + + if addLocalRot: + for constraint in bone.constraints: + if constraint.type == 'COPY_ROTATION': + constraint.target_space = 'LOCAL' + constraint.owner_space = 'LOCAL_WITH_PARENT' + + +def prepareForBake(enduser_obj): + bones = enduser_obj.pose.bones + for bone in bones: + bone.bone.select = False + map_bones = [bone for bone in bones if bone.bone.reverseMap] + for bone in map_bones: + for cons in bone.constraints: + if "retargetTemp" in cons.name: + bone.bone.select = True + +def cleanTempConstraints(enduser_obj): + bones = enduser_obj.pose.bones + map_bones = [bone for bone in bones if bone.bone.reverseMap] + for bone in map_bones: + for cons in bone.constraints: + if "retargetTemp" in cons.name: + bone.constraints.remove(cons) + #Main function that runs the retargeting sequence. +#If advanced == True, we assume constraint's were already created def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): perf_arm = performer_obj.data end_arm = enduser_obj.data + advanced = end_arm.advancedRetarget try: enduser_obj.animation_data.action = bpy.data.actions.new("temp") @@ -450,27 +511,33 @@ def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): except: print("no need to create new action") - print("creating Dictionary") feetBones, root = createDictionary(perf_arm, end_arm) print("cleaning stuff up") perf_obj_mat, enduser_obj_mat = cleanAndStoreObjMat(performer_obj, enduser_obj) - turnOffIK(enduser_obj) - print("Creating intermediate armature (for first pass)") - inter_obj = createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene) - print("First pass: retargeting from intermediate to end user") - - - retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene) + if not advanced: + turnOffIK(enduser_obj) + print("Creating intermediate armature (for first pass)") + inter_obj = createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene) + print("First pass: retargeting from intermediate to end user") + retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene) + else: + prepareForBake(enduser_obj) + print("Retargeting pose (Advanced Retarget)") + nla.bake(s_frame, e_frame, action=enduser_obj.animation_data.action, only_selected=True, do_pose=True, do_object=False) name = performer_obj.animation_data.action.name enduser_obj.animation_data.action.name = "Base " + name print("Second pass: retargeting root translation and clean up") stride_bone = copyTranslation(performer_obj, enduser_obj, feetBones, root, s_frame, e_frame, scene, enduser_obj_mat) - IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene) + if not advanced: + IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene) restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone) bpy.ops.object.mode_set(mode='OBJECT') - bpy.ops.object.select_name(name=inter_obj.name, extend=False) - bpy.ops.object.delete() + if not advanced: + bpy.ops.object.select_name(name=inter_obj.name, extend=False) + bpy.ops.object.delete() + else: + cleanTempConstraints(enduser_obj) bpy.ops.object.select_name(name=enduser_obj.name, extend=False) if not name in [tracks.name for tracks in end_arm.mocapNLATracks]: diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 0788366547e..06d0bb0b415 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -140,9 +140,26 @@ class MocapNLATracks(bpy.types.PropertyGroup): bpy.utils.register_class(MocapNLATracks) + +def advancedRetargetToggle(self, context): + enduser_obj = context.active_object + performer_obj = [obj for obj in context.selected_objects if obj != enduser_obj] + if enduser_obj is None or len(performer_obj) != 1: + print("Need active and selected armatures") + return + else: + performer_obj = performer_obj[0] + if self.advancedRetarget: + retarget.preAdvancedRetargeting(performer_obj, enduser_obj) + else: + retarget.cleanTempConstraints(enduser_obj) + + + bpy.types.Armature.stitch_settings = bpy.props.PointerProperty(type=AnimationStitchSettings) bpy.types.Armature.active_mocap = bpy.props.StringProperty(update=retarget.NLASystemInitialize) bpy.types.Armature.mocapNLATracks = bpy.props.CollectionProperty(type=MocapNLATracks) +bpy.types.Armature.advancedRetarget = bpy.props.BoolProperty(default=False, update=advancedRetargetToggle) #Update function for IK functionality. Is called when IK prop checkboxes are toggled. @@ -189,7 +206,7 @@ def toggleIKBone(self, context): for bone in cnstrn_bone.parent_recursive: if not bone.is_in_ik_chain: bone.IKRetarget = False - + class MocapMapping(bpy.types.PropertyGroup): name = bpy.props.StringProperty() @@ -281,6 +298,7 @@ class MocapPanel(bpy.types.Panel): mapRow.operator("mocap.savemapping", text='Save mapping') mapRow.operator("mocap.loadmapping", text='Load mapping') self.layout.prop(data=performer_obj.animation_data.action, property='name', text='Action Name') + self.layout.prop(enduser_arm, "advancedRetarget", text='Advanced Retarget') self.layout.operator("mocap.retarget", text='RETARGET!') @@ -396,6 +414,35 @@ class OBJECT_OT_RetargetButton(bpy.types.Operator): return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) else: return False + + + #~ class OBJECT_OT_AdvancedRetargetButton(bpy.types.Operator): + #~ '''Prepare for advanced retargeting ''' + #~ bl_idname = "mocap.preretarget" + #~ bl_label = "Prepares retarget of active action from Performer to Enduser" + + #~ def execute(self, context): + #~ scene = context.scene + #~ s_frame = scene.frame_start + #~ e_frame = scene.frame_end + #~ enduser_obj = context.active_object + #~ performer_obj = [obj for obj in context.selected_objects if obj != enduser_obj] + #~ if enduser_obj is None or len(performer_obj) != 1: + #~ print("Need active and selected armatures") + #~ else: + #~ performer_obj = performer_obj[0] + #~ retarget.preAdvancedRetargeting(performer_obj, enduser_obj) + #~ return {"FINISHED"} + + #~ @classmethod + #~ def poll(cls, context): + #~ if context.active_object: + #~ activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) + #~ performer_obj = [obj for obj in context.selected_objects if obj != context.active_object] + #~ if performer_obj: + #~ return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) + #~ else: + #~ return False class OBJECT_OT_SaveMappingButton(bpy.types.Operator): @@ -715,7 +762,7 @@ class OBJECT_OT_AnimationStitchingButton(bpy.types.Operator): stitch_settings = context.active_object.data.stitch_settings return (stitch_settings.first_action and stitch_settings.second_action) return False - + def register(): bpy.utils.register_module(__name__) -- cgit v1.2.3 From 05b7ccb736b88b806d4df3c2f83aff9773756099 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Thu, 11 Aug 2011 14:50:19 +0000 Subject: Optimizations following intensive profiling of retarget and other lengthy functions. Retargeting now takes ~30% less time --- release/scripts/modules/mocap_tools.py | 9 ++---- release/scripts/modules/retarget.py | 55 +++++++++++++++++++++------------- release/scripts/startup/ui_mocap.py | 1 + 3 files changed, 39 insertions(+), 26 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index b490d571dd8..3f821270e3c 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -660,15 +660,12 @@ def limit_dof(context, performer_obj, enduser_obj): srcParent = bone.parent parent_mat = srcParent.matrix parent_rest = end_bone.parent.bone.matrix_local - parent_rest_inv = parent_rest.copy() - parent_rest_inv.invert() - parent_mat_inv = parent_mat.copy() - parent_mat_inv.invert() + parent_rest_inv = parent_rest.inverted() + parent_mat_inv = parent_mat.inverted() bake_matrix = parent_mat_inv * bake_matrix rest_matrix = parent_rest_inv * rest_matrix - rest_matrix_inv = rest_matrix.copy() - rest_matrix_inv.invert() + rest_matrix_inv = rest_matrix.inverted() bake_matrix = rest_matrix_inv * bake_matrix mat = bake_matrix diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 88a5c3a620a..0235bfc1474 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -79,8 +79,7 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene def singleBoneRetarget(inter_bone, perf_bone): perf_world_rotation = perf_bone.matrix * performer_obj.matrix_world inter_world_base_rotation = inter_bone.bone.matrix_local * inter_obj.matrix_world - inter_world_base_inv = Matrix(inter_world_base_rotation) - inter_world_base_inv.invert() + inter_world_base_inv = inter_world_base_rotation.inverted() return (inter_world_base_inv.to_3x3() * perf_world_rotation.to_3x3()).to_4x4() #uses 1to1 and interpolation/averaging to match many to 1 retarget @@ -178,15 +177,12 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene): srcParent = srcParent.parent parent_mat = srcParent.matrix parent_rest = trg_bone.parent.bone.matrix_local - parent_rest_inv = parent_rest.copy() - parent_rest_inv.invert() - parent_mat_inv = parent_mat.copy() - parent_mat_inv.invert() + parent_rest_inv = parent_rest.inverted() + parent_mat_inv = parent_mat.inverted() bake_matrix = parent_mat_inv * bake_matrix rest_matrix = parent_rest_inv * rest_matrix - rest_matrix_inv = rest_matrix.copy() - rest_matrix_inv.invert() + rest_matrix_inv = rest_matrix.inverted() bake_matrix = rest_matrix_inv * bake_matrix end_bone.matrix_basis = bake_matrix rot_mode = end_bone.rotation_mode @@ -247,26 +243,29 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame # now we take our locDict and analyze it. # we need to derive all chains + + def locDeriv(key, t): + graph = locDict[key] + return graph[t + 1] - graph[t] - locDeriv = {} - for key in locDictKeys: - locDeriv[key] = [] + #~ locDeriv = {} + #~ for key in locDictKeys: + #~ locDeriv[key] = [] - for key in locDict.keys(): - graph = locDict[key] - locDeriv[key] = [graph[t + 1] - graph[t] for t in range(len(graph) - 1)] + #~ for key in locDict.keys(): + #~ graph = locDict[key] + #~ locDeriv[key] = [graph[t + 1] - graph[t] for t in range(len(graph) - 1)] # now find the plant frames, where perfFeet don't move much linearAvg = [] for key in perfFeet: - for i in range(len(locDeriv[key]) - 1): - v = locDeriv[key][i] - hipV = locDeriv[perfRoot][i] - endV = locDeriv[perf_bones[key].bone.map][i] - print(v.length,) + for i in range(len(locDict[key]) - 1): + v = locDeriv(key,i) if (v.length < 0.1): + hipV = locDeriv(perfRoot,i) + endV = locDeriv(perf_bones[key].bone.map,i) #this is a plant frame. #lets see what the original hip delta is, and the corresponding #end bone's delta @@ -547,6 +546,22 @@ def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): NLATracks = end_arm.mocapNLATracks[name] end_arm.active_mocap = name print("retargeting done!") + +def profileWrapper(): + context = bpy.context + scene = context.scene + s_frame = scene.frame_start + e_frame = scene.frame_end + enduser_obj = context.active_object + performer_obj = [obj for obj in context.selected_objects if obj != enduser_obj] + if enduser_obj is None or len(performer_obj) != 1: + print("Need active and selected armatures") + else: + performer_obj = performer_obj[0] + s_frame, e_frame = performer_obj.animation_data.action.frame_range + s_frame = int(s_frame) + e_frame = int(e_frame) + totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame) if __name__ == "__main__": - totalRetarget() + cProfile.run("profileWrapper()") diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 06d0bb0b415..dd5e6fa5d6d 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -25,6 +25,7 @@ from bpy import * import mocap_constraints import retarget import mocap_tools + ### reloads modules (for testing purposes only) from imp import reload reload(mocap_constraints) -- cgit v1.2.3 From f1a8c26aa3a8e3e3628d279ad32f3e1ea261a695 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Thu, 11 Aug 2011 16:46:27 +0000 Subject: Additional work on animation stitching, now with auto-guess capability. Only a few bugs left, regarding animations translation --- release/scripts/modules/mocap_tools.py | 90 ++++++++++++++++++++++------------ release/scripts/modules/retarget.py | 27 ++++++---- release/scripts/startup/ui_mocap.py | 20 ++++++++ 3 files changed, 96 insertions(+), 41 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index 3f821270e3c..f4b6a93f531 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -105,64 +105,75 @@ class dataPoint: self.u = u -def autoloop_anim(): - context = bpy.context - obj = context.active_object - fcurves = [x for x in obj.animation_data.action.fcurves if x.select] - - data = [] - end = len(fcurves[0].keyframe_points) +def crossCorrelationMatch(curvesA, curvesB, margin): + dataA = [] + dataB = [] + end = len(curvesA[0].keyframe_points) for i in range(1, end): vec = [] - for fcurve in fcurves: + for fcurve in curvesA: vec.append(fcurve.evaluate(i)) - data.append(NdVector(vec)) + dataA.append(NdVector(vec)) + vec = [] + for fcurve in curvesB: + vec.append(fcurve.evaluate(i)) + dataB.append(NdVector(vec)) def comp(a, b): return a * b - N = len(data) + N = len(dataA) Rxy = [0.0] * N for i in range(N): for j in range(i, min(i + N, N)): - Rxy[i] += comp(data[j], data[j - i]) + Rxy[i] += comp(dataA[j], dataB[j - i]) for j in range(i): - Rxy[i] += comp(data[j], data[j - i + N]) + Rxy[i] += comp(dataA[j], dataB[j - i + N]) Rxy[i] /= float(N) - def bestLocalMaximum(Rxy): Rxyd = [Rxy[i] - Rxy[i - 1] for i in range(1, len(Rxy))] maxs = [] for i in range(1, len(Rxyd) - 1): a = Rxyd[i - 1] b = Rxyd[i] - print(a, b) #sign change (zerocrossing) at point i, denoting max point (only) if (a >= 0 and b < 0) or (a < 0 and b >= 0): maxs.append((i, max(Rxy[i], Rxy[i - 1]))) - return max(maxs, key=lambda x: x[1])[0] - flm = bestLocalMaximum(Rxy[0:int(len(Rxy))]) - - diff = [] - - for i in range(len(data) - flm): - diff.append((data[i] - data[i + flm]).lengthSq) + return [x[0] for x in maxs] + #~ return max(maxs, key=lambda x: x[1])[0] + + flms = bestLocalMaximum(Rxy[0:int(len(Rxy))]) + ss = [] + for flm in flms: + diff = [] + + for i in range(len(dataA) - flm): + diff.append((dataA[i] - dataB[i + flm]).lengthSq) + + def lowerErrorSlice(diff, e): + #index, error at index + bestSlice = (0, 100000) + for i in range(e, len(diff) - e): + errorSlice = sum(diff[i - e:i + e + 1]) + if errorSlice < bestSlice[1]: + bestSlice = (i, errorSlice, flm) + return bestSlice + + s = lowerErrorSlice(diff, margin) + ss.append(s) - def lowerErrorSlice(diff, e): - #index, error at index - bestSlice = (0, 100000) - for i in range(e, len(diff) - e): - errorSlice = sum(diff[i - e:i + e + 1]) - if errorSlice < bestSlice[1]: - bestSlice = (i, errorSlice) - return bestSlice[0] + ss.sort(key = lambda x: x[1]) + return ss[0][2], ss[0][0], dataA - margin = 2 +def autoloop_anim(): + context = bpy.context + obj = context.active_object + fcurves = [x for x in obj.animation_data.action.fcurves if x.select] - s = lowerErrorSlice(diff, margin) + margin = 10 - print(flm, s) + flm, s, data = crossCorrelationMatch(fcurves, fcurves, margin) loop = data[s:s + flm + margin] #find *all* loops, s:s+flm, s+flm:s+2flm, etc... @@ -824,3 +835,18 @@ def anim_stitch(context, enduser_obj): pt.handle_left.y-=offset[i] pt.handle_right.y-=offset[i] + +def guess_anim_stitch(context, enduser_obj): + stitch_settings = enduser_obj.data.stitch_settings + action_1 = stitch_settings.first_action + action_2 = stitch_settings.second_action + TrackNamesA = enduser_obj.data.mocapNLATracks[action_1] + TrackNamesB = enduser_obj.data.mocapNLATracks[action_2] + mocapA = bpy.data.actions[TrackNamesA.base_track] + mocapB = bpy.data.actions[TrackNamesB.base_track] + curvesA = mocapA.fcurves + curvesB = mocapB.fcurves + flm, s, data = crossCorrelationMatch(curvesA, curvesB, 10) + print(flm,s) + enduser_obj.data.stitch_settings.blend_frame = flm + enduser_obj.data.stitch_settings.second_offset = s \ No newline at end of file diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 0235bfc1474..827d3d11ddc 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -305,6 +305,7 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame def IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene): + bpy.ops.object.select_name(name=enduser_obj.name, extend=False) end_bones = enduser_obj.pose.bones for pose_bone in end_bones: ik_constraint = hasIKConstraint(pose_bone) @@ -313,9 +314,12 @@ def IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene): # set constraint target to corresponding empty if targetless, # if not, keyframe current target to corresponding empty perf_bone = pose_bone.bone.reverseMap[-1].name + bpy.ops.object.mode_set(mode='EDIT') orgLocTrg = originalLocationTarget(pose_bone, enduser_obj) + bpy.ops.object.mode_set(mode='OBJECT') if not ik_constraint.target: - ik_constraint.target = orgLocTrg + ik_constraint.target = enduser_obj + ik_constraint.subtarget = pose_bone.name+"IK" target = orgLocTrg # There is a target now @@ -337,6 +341,7 @@ def IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene): target.keyframe_insert("location") ik_constraint.mute = False scene.frame_set(s_frame) + bpy.ops.object.mode_set(mode='OBJECT') def turnOffIK(enduser_obj): @@ -379,14 +384,17 @@ def restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, str #create (or return if exists) the related IK empty to the bone def originalLocationTarget(end_bone, enduser_obj): - if not end_bone.name + "Org" in bpy.data.objects: - bpy.ops.object.add() - empty = bpy.context.active_object - empty.name = end_bone.name + "Org" - empty.empty_draw_size = 0.1 - empty.parent = enduser_obj - empty = bpy.data.objects[end_bone.name + "Org"] - return empty + if not end_bone.name + "IK" in enduser_obj.data.bones: + newBone = enduser_obj.data.edit_bones.new(end_bone.name + "IK") + newBone.head = end_bone.tail + newBone.tail = end_bone.tail + Vector((0,0.1,0)) + #~ empty = bpy.context.active_object + #~ empty.name = end_bone.name + "Org" + #~ empty.empty_draw_size = 0.1 + #~ empty.parent = enduser_obj + else: + newBone = enduser_obj.pose.bones[end_bone.name + "IK"] + return newBone #create the specified NLA setup for base animation, constraints and tweak layer. @@ -530,6 +538,7 @@ def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): stride_bone = copyTranslation(performer_obj, enduser_obj, feetBones, root, s_frame, e_frame, scene, enduser_obj_mat) if not advanced: IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene) + bpy.ops.object.select_name(name=stride_bone.name, extend=False) restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone) bpy.ops.object.mode_set(mode='OBJECT') if not advanced: diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index dd5e6fa5d6d..19a96750e49 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -382,6 +382,7 @@ class ExtraToolsPanel(bpy.types.Panel): layout.prop(settings, "blend_amount") layout.prop(settings, "second_offset") layout.prop_search(settings, "stick_bone", context.active_object.pose, "bones") + layout.operator('mocap.animstitchguess', text="Guess Settings") layout.operator('mocap.animstitch', text="Stitch Animations") @@ -765,6 +766,25 @@ class OBJECT_OT_AnimationStitchingButton(bpy.types.Operator): return False +class OBJECT_OT_GuessAnimationStitchingButton(bpy.types.Operator): + '''Guesses the stitch frame and second offset for animation stitch''' + bl_idname = "mocap.animstitchguess" + bl_label = "Guesses the stitch frame and second offset for animation stitch" + + def execute(self, context): + mocap_tools.guess_anim_stitch(context, context.active_object) + return {"FINISHED"} + + @classmethod + def poll(cls, context): + activeIsArmature = False + if context.active_object: + activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) + if activeIsArmature: + stitch_settings = context.active_object.data.stitch_settings + return (stitch_settings.first_action and stitch_settings.second_action) + return False + def register(): bpy.utils.register_module(__name__) -- cgit v1.2.3 From ada88c8d8ed051465e8db7ba0b856a6b065cb2d5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Aug 2011 06:08:22 +0000 Subject: sequencer todo: change sequence added back (C key) split up into operators - change effect input - change effect type - change file data Change plugin is not ported back yet. --- release/scripts/startup/bl_ui/space_sequencer.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index c477a2ff62b..56589188d0d 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -169,6 +169,19 @@ class SEQUENCER_MT_marker(bpy.types.Menu): #layout.operator("sequencer.sound_strip_add", text="Transform Markers") # toggle, will be rna - (sseq->flag & SEQ_MARKER_TRANS) +class SEQUENCER_MT_change(bpy.types.Menu): + bl_label = "Change" + + def draw(self, context): + layout = self.layout + + layout.operator_context = 'INVOKE_REGION_WIN' + + layout.operator_menu_enum("sequencer.change_effect_input", "swap") + layout.operator_menu_enum("sequencer.change_effect_type", "type") + layout.operator("sequencer.change_path", text="Path/Files") + + class SEQUENCER_MT_add(bpy.types.Menu): bl_label = "Add" @@ -292,6 +305,7 @@ class SEQUENCER_MT_strip(bpy.types.Menu): layout.separator() layout.operator("sequencer.swap_data") + layout.menu("SEQUENCER_MT_change") class SequencerButtonsPanel(): -- cgit v1.2.3 From 8fd246cb708569eff223c2da145395cc5ef99402 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Aug 2011 06:31:39 +0000 Subject: add bpy.types as a module for convenient imports, eg: from bpy.types import Menu --- release/scripts/modules/bpy/__init__.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/bpy/__init__.py b/release/scripts/modules/bpy/__init__.py index a43b42e49a1..5c371fd750a 100644 --- a/release/scripts/modules/bpy/__init__.py +++ b/release/scripts/modules/bpy/__init__.py @@ -44,14 +44,18 @@ from . import utils, path, ops ops = ops.ops_fake_module -def _main(): - import sys as _sys +def main(): + import sys # Possibly temp. addons path from os.path import join, dirname, normpath - _sys.path.append(normpath(join(dirname(__file__), + sys.path.append(normpath(join(dirname(__file__), "..", "..", "addons", "modules"))) + # fake module to allow: + # from bpy.types import Panel + sys.modules["bpy.types"] = types + # if "-d" in sys.argv: # Enable this to measure startup speed if 0: import cProfile @@ -65,6 +69,6 @@ def _main(): utils.load_scripts() -_main() +main() -del _main +del main -- cgit v1.2.3 From b374ab919a4b46d377d88ad0f1f1eced06621eca Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Aug 2011 06:57:00 +0000 Subject: import common classes from bpy.types, saves ~1000 python getattrs on startup. --- .../scripts/startup/bl_operators/add_mesh_torus.py | 3 +- .../scripts/startup/bl_operators/animsys_update.py | 3 +- release/scripts/startup/bl_operators/image.py | 9 +- release/scripts/startup/bl_operators/mesh.py | 5 +- release/scripts/startup/bl_operators/nla.py | 3 +- release/scripts/startup/bl_operators/object.py | 19 ++- .../scripts/startup/bl_operators/object_align.py | 3 +- .../startup/bl_operators/object_quick_effects.py | 9 +- .../bl_operators/object_randomize_transform.py | 3 +- release/scripts/startup/bl_operators/presets.py | 23 +-- .../bl_operators/screen_play_rendered_anim.py | 3 +- release/scripts/startup/bl_operators/sequencer.py | 7 +- .../startup/bl_operators/uvcalc_follow_active.py | 3 +- .../startup/bl_operators/uvcalc_lightmap.py | 3 +- .../startup/bl_operators/uvcalc_smart_project.py | 3 +- .../startup/bl_operators/vertexpaint_dirt.py | 3 +- release/scripts/startup/bl_operators/wm.py | 65 ++++---- .../startup/bl_ui/properties_data_armature.py | 21 +-- .../scripts/startup/bl_ui/properties_data_bone.py | 17 +- .../startup/bl_ui/properties_data_camera.py | 9 +- .../scripts/startup/bl_ui/properties_data_curve.py | 21 +-- .../scripts/startup/bl_ui/properties_data_empty.py | 3 +- .../scripts/startup/bl_ui/properties_data_lamp.py | 23 +-- .../startup/bl_ui/properties_data_lattice.py | 7 +- .../scripts/startup/bl_ui/properties_data_mesh.py | 23 +-- .../startup/bl_ui/properties_data_metaball.py | 11 +- .../startup/bl_ui/properties_data_modifier.py | 3 +- release/scripts/startup/bl_ui/properties_game.py | 27 +-- .../scripts/startup/bl_ui/properties_material.py | 53 +++--- release/scripts/startup/bl_ui/properties_object.py | 25 +-- .../startup/bl_ui/properties_object_constraint.py | 5 +- .../scripts/startup/bl_ui/properties_particle.py | 31 ++-- .../startup/bl_ui/properties_physics_cloth.py | 15 +- .../startup/bl_ui/properties_physics_common.py | 3 +- .../startup/bl_ui/properties_physics_field.py | 5 +- .../startup/bl_ui/properties_physics_fluid.py | 9 +- .../startup/bl_ui/properties_physics_smoke.py | 11 +- .../startup/bl_ui/properties_physics_softbody.py | 15 +- release/scripts/startup/bl_ui/properties_render.py | 37 +++-- release/scripts/startup/bl_ui/properties_scene.py | 17 +- .../scripts/startup/bl_ui/properties_texture.py | 51 +++--- release/scripts/startup/bl_ui/properties_world.py | 21 +-- release/scripts/startup/bl_ui/space_console.py | 15 +- release/scripts/startup/bl_ui/space_dopesheet.py | 19 ++- release/scripts/startup/bl_ui/space_filebrowser.py | 3 +- release/scripts/startup/bl_ui/space_graph.py | 15 +- release/scripts/startup/bl_ui/space_image.py | 51 +++--- release/scripts/startup/bl_ui/space_info.py | 33 ++-- release/scripts/startup/bl_ui/space_logic.py | 9 +- release/scripts/startup/bl_ui/space_nla.py | 15 +- release/scripts/startup/bl_ui/space_node.py | 11 +- release/scripts/startup/bl_ui/space_outliner.py | 9 +- release/scripts/startup/bl_ui/space_sequencer.py | 37 +++-- release/scripts/startup/bl_ui/space_text.py | 25 +-- release/scripts/startup/bl_ui/space_time.py | 13 +- release/scripts/startup/bl_ui/space_userpref.py | 43 ++--- .../scripts/startup/bl_ui/space_userpref_keymap.py | 25 +-- release/scripts/startup/bl_ui/space_view3d.py | 181 +++++++++++---------- .../scripts/startup/bl_ui/space_view3d_toolbar.py | 55 ++++--- 59 files changed, 624 insertions(+), 565 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py index 27a6d21d519..1c4518c4feb 100644 --- a/release/scripts/startup/bl_operators/add_mesh_torus.py +++ b/release/scripts/startup/bl_operators/add_mesh_torus.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Operator import mathutils @@ -81,7 +82,7 @@ from bpy.props import (FloatProperty, ) -class AddTorus(bpy.types.Operator): +class AddTorus(Operator): '''Add a torus mesh''' bl_idname = "mesh.primitive_torus_add" bl_label = "Add Torus" diff --git a/release/scripts/startup/bl_operators/animsys_update.py b/release/scripts/startup/bl_operators/animsys_update.py index 63d438a5066..3710c57ac16 100644 --- a/release/scripts/startup/bl_operators/animsys_update.py +++ b/release/scripts/startup/bl_operators/animsys_update.py @@ -686,9 +686,10 @@ data_path_update = [ import bpy +from bpy.types import Operator -class UpdateAnimData(bpy.types.Operator): +class UpdateAnimData(Operator): """Update data paths from 2.56 and previous versions, modifying data paths of drivers and fcurves""" bl_idname = "anim.update_data_paths" bl_label = "Update Animation Data" diff --git a/release/scripts/startup/bl_operators/image.py b/release/scripts/startup/bl_operators/image.py index aca9b581b97..9226cbed51b 100644 --- a/release/scripts/startup/bl_operators/image.py +++ b/release/scripts/startup/bl_operators/image.py @@ -19,10 +19,11 @@ # import bpy +from bpy.types import Operator from bpy.props import StringProperty -class EditExternally(bpy.types.Operator): +class EditExternally(Operator): '''Edit image in an external application''' bl_idname = "image.external_edit" bl_label = "Image Edit Externally" @@ -106,7 +107,7 @@ class EditExternally(bpy.types.Operator): return {'FINISHED'} -class SaveDirty(bpy.types.Operator): +class SaveDirty(Operator): """Save all modified textures""" bl_idname = "image.save_dirty" bl_label = "Save Dirty" @@ -129,7 +130,7 @@ class SaveDirty(bpy.types.Operator): return {'FINISHED'} -class ProjectEdit(bpy.types.Operator): +class ProjectEdit(Operator): """Edit a snapshot of the viewport in an external image editor""" bl_idname = "image.project_edit" bl_label = "Project Edit" @@ -196,7 +197,7 @@ class ProjectEdit(bpy.types.Operator): return {'FINISHED'} -class ProjectApply(bpy.types.Operator): +class ProjectApply(Operator): """Project edited image back onto the object""" bl_idname = "image.project_apply" bl_label = "Project Apply" diff --git a/release/scripts/startup/bl_operators/mesh.py b/release/scripts/startup/bl_operators/mesh.py index 344b238709f..4114381f3dc 100644 --- a/release/scripts/startup/bl_operators/mesh.py +++ b/release/scripts/startup/bl_operators/mesh.py @@ -19,11 +19,12 @@ # import bpy +from bpy.types import Operator from bpy.props import EnumProperty -class MeshSelectInteriorFaces(bpy.types.Operator): +class MeshSelectInteriorFaces(Operator): '''Select faces where all edges have more then 2 face users.''' bl_idname = "mesh.faces_select_interior" @@ -67,7 +68,7 @@ class MeshSelectInteriorFaces(bpy.types.Operator): return {'FINISHED'} -class MeshMirrorUV(bpy.types.Operator): +class MeshMirrorUV(Operator): '''Copy mirror UV coordinates on the X axis based on a mirrored mesh''' bl_idname = "mesh.faces_mirror_uv" bl_label = "Copy Mirrored UV coords" diff --git a/release/scripts/startup/bl_operators/nla.py b/release/scripts/startup/bl_operators/nla.py index 469e9015e62..44ed846e530 100644 --- a/release/scripts/startup/bl_operators/nla.py +++ b/release/scripts/startup/bl_operators/nla.py @@ -19,6 +19,7 @@ # import bpy +from bpy.types import Operator def pose_frame_info(obj): @@ -191,7 +192,7 @@ def bake(frame_start, from bpy.props import IntProperty, BoolProperty, EnumProperty -class BakeAction(bpy.types.Operator): +class BakeAction(Operator): '''Bake animation to an Action''' bl_idname = "nla.bake" bl_label = "Bake Action" diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py index 627a1530fe1..79f57990f37 100644 --- a/release/scripts/startup/bl_operators/object.py +++ b/release/scripts/startup/bl_operators/object.py @@ -19,10 +19,11 @@ # import bpy +from bpy.types import Operator from bpy.props import StringProperty, BoolProperty, EnumProperty, IntProperty -class SelectPattern(bpy.types.Operator): +class SelectPattern(Operator): '''Select object matching a naming pattern''' bl_idname = "object.select_pattern" bl_label = "Select Pattern" @@ -99,7 +100,7 @@ class SelectPattern(bpy.types.Operator): row.prop(self, "extend") -class SelectCamera(bpy.types.Operator): +class SelectCamera(Operator): '''Select object matching a naming pattern''' bl_idname = "object.select_camera" bl_label = "Select Camera" @@ -120,7 +121,7 @@ class SelectCamera(bpy.types.Operator): return {'FINISHED'} -class SelectHierarchy(bpy.types.Operator): +class SelectHierarchy(Operator): '''Select object relative to the active objects position''' \ '''in the hierarchy''' bl_idname = "object.select_hierarchy" @@ -187,7 +188,7 @@ class SelectHierarchy(bpy.types.Operator): return {'CANCELLED'} -class SubdivisionSet(bpy.types.Operator): +class SubdivisionSet(Operator): '''Sets a Subdivision Surface Level (1-5)''' bl_idname = "object.subdivision_set" @@ -263,7 +264,7 @@ class SubdivisionSet(bpy.types.Operator): return {'FINISHED'} -class ShapeTransfer(bpy.types.Operator): +class ShapeTransfer(Operator): '''Copy another selected objects active shape to this one by ''' \ '''applying the relative offsets''' @@ -507,7 +508,7 @@ class ShapeTransfer(bpy.types.Operator): return self._main(ob_act, objects, self.mode, self.use_clamp) -class JoinUVs(bpy.types.Operator): +class JoinUVs(Operator): '''Copy UV Layout to objects with matching geometry''' bl_idname = "object.join_uvs" bl_label = "Join as UVs" @@ -575,7 +576,7 @@ class JoinUVs(bpy.types.Operator): return {'FINISHED'} -class MakeDupliFace(bpy.types.Operator): +class MakeDupliFace(Operator): '''Make linked objects into dupli-faces''' bl_idname = "object.make_dupli_face" bl_label = "Make Dupli-Face" @@ -649,7 +650,7 @@ class MakeDupliFace(bpy.types.Operator): return {'FINISHED'} -class IsolateTypeRender(bpy.types.Operator): +class IsolateTypeRender(Operator): '''Hide unselected render objects of same type as active ''' \ '''by setting the hide render flag''' bl_idname = "object.isolate_type_render" @@ -670,7 +671,7 @@ class IsolateTypeRender(bpy.types.Operator): return {'FINISHED'} -class ClearAllRestrictRender(bpy.types.Operator): +class ClearAllRestrictRender(Operator): '''Reveal all render objects by setting the hide render flag''' bl_idname = "object.hide_render_clear_all" bl_label = "Clear All Restrict Render" diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py index 7fd769c40c9..d4a3d826f2f 100644 --- a/release/scripts/startup/bl_operators/object_align.py +++ b/release/scripts/startup/bl_operators/object_align.py @@ -19,6 +19,7 @@ # import bpy +from bpy.types import Operator from mathutils import Vector @@ -339,7 +340,7 @@ def align_objects(align_x, from bpy.props import EnumProperty, BoolProperty -class AlignObjects(bpy.types.Operator): +class AlignObjects(Operator): '''Align Objects''' bl_idname = "object.align" bl_label = "Align Objects" diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py index ef10bfd737d..cd206da3a8e 100644 --- a/release/scripts/startup/bl_operators/object_quick_effects.py +++ b/release/scripts/startup/bl_operators/object_quick_effects.py @@ -20,6 +20,7 @@ from mathutils import Vector import bpy +from bpy.types import Operator from bpy.props import (BoolProperty, EnumProperty, IntProperty, @@ -45,7 +46,7 @@ def object_ensure_material(obj, mat_name): return mat -class QuickFur(bpy.types.Operator): +class QuickFur(Operator): bl_idname = "object.quick_fur" bl_label = "Quick Fur" bl_options = {'REGISTER', 'UNDO'} @@ -104,7 +105,7 @@ class QuickFur(bpy.types.Operator): return {'FINISHED'} -class QuickExplode(bpy.types.Operator): +class QuickExplode(Operator): bl_idname = "object.quick_explode" bl_label = "Quick Explode" bl_options = {'REGISTER', 'UNDO'} @@ -265,7 +266,7 @@ def obj_bb_minmax(obj, min_co, max_co): max_co[2] = max(bb_vec[2], max_co[2]) -class QuickSmoke(bpy.types.Operator): +class QuickSmoke(Operator): bl_idname = "object.quick_smoke" bl_label = "Quick Smoke" bl_options = {'REGISTER', 'UNDO'} @@ -383,7 +384,7 @@ class QuickSmoke(bpy.types.Operator): return {'FINISHED'} -class QuickFluid(bpy.types.Operator): +class QuickFluid(Operator): bl_idname = "object.quick_fluid" bl_label = "Quick Fluid" bl_options = {'REGISTER', 'UNDO'} diff --git a/release/scripts/startup/bl_operators/object_randomize_transform.py b/release/scripts/startup/bl_operators/object_randomize_transform.py index b94c4f06cd3..f65e3d27d83 100644 --- a/release/scripts/startup/bl_operators/object_randomize_transform.py +++ b/release/scripts/startup/bl_operators/object_randomize_transform.py @@ -19,6 +19,7 @@ # import bpy +from bpy.types import Operator def randomize_selected(seed, delta, loc, rot, scale, scale_even): @@ -87,7 +88,7 @@ def randomize_selected(seed, delta, loc, rot, scale, scale_even): from bpy.props import IntProperty, BoolProperty, FloatVectorProperty -class RandomizeLocRotSize(bpy.types.Operator): +class RandomizeLocRotSize(Operator): '''Randomize objects loc/rot/scale''' bl_idname = "object.randomize_transform" bl_label = "Randomize Transform" diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py index fbcc327c3bd..2fd0c4a9e12 100644 --- a/release/scripts/startup/bl_operators/presets.py +++ b/release/scripts/startup/bl_operators/presets.py @@ -19,6 +19,7 @@ # import bpy +from bpy.types import Menu, Operator class AddPresetBase(): @@ -140,7 +141,7 @@ class AddPresetBase(): return self.execute(context) -class ExecutePreset(bpy.types.Operator): +class ExecutePreset(Operator): ''' Executes a preset ''' bl_idname = "script.execute_preset" bl_label = "Execute a Python Preset" @@ -168,7 +169,7 @@ class ExecutePreset(bpy.types.Operator): return {'FINISHED'} -class AddPresetRender(AddPresetBase, bpy.types.Operator): +class AddPresetRender(AddPresetBase, Operator): '''Add a Render Preset''' bl_idname = "render.preset_add" bl_label = "Add Render Preset" @@ -194,7 +195,7 @@ class AddPresetRender(AddPresetBase, bpy.types.Operator): preset_subdir = "render" -class AddPresetSSS(AddPresetBase, bpy.types.Operator): +class AddPresetSSS(AddPresetBase, Operator): '''Add a Subsurface Scattering Preset''' bl_idname = "material.sss_preset_add" bl_label = "Add SSS Preset" @@ -222,7 +223,7 @@ class AddPresetSSS(AddPresetBase, bpy.types.Operator): preset_subdir = "sss" -class AddPresetCloth(AddPresetBase, bpy.types.Operator): +class AddPresetCloth(AddPresetBase, Operator): '''Add a Cloth Preset''' bl_idname = "cloth.preset_add" bl_label = "Add Cloth Preset" @@ -244,7 +245,7 @@ class AddPresetCloth(AddPresetBase, bpy.types.Operator): preset_subdir = "cloth" -class AddPresetSunSky(AddPresetBase, bpy.types.Operator): +class AddPresetSunSky(AddPresetBase, Operator): '''Add a Sky & Atmosphere Preset''' bl_idname = "lamp.sunsky_preset_add" bl_label = "Add Sunsky Preset" @@ -273,7 +274,7 @@ class AddPresetSunSky(AddPresetBase, bpy.types.Operator): preset_subdir = "sunsky" -class AddPresetInteraction(AddPresetBase, bpy.types.Operator): +class AddPresetInteraction(AddPresetBase, Operator): '''Add an Application Interaction Preset''' bl_idname = "wm.interaction_preset_add" bl_label = "Add Interaction Preset" @@ -299,7 +300,7 @@ class AddPresetInteraction(AddPresetBase, bpy.types.Operator): preset_subdir = "interaction" -class AddPresetKeyconfig(AddPresetBase, bpy.types.Operator): +class AddPresetKeyconfig(AddPresetBase, Operator): '''Add a Keyconfig Preset''' bl_idname = "wm.keyconfig_preset_add" bl_label = "Add Keyconfig Preset" @@ -322,7 +323,7 @@ class AddPresetKeyconfig(AddPresetBase, bpy.types.Operator): keyconfigs.remove(keyconfigs.active) -class AddPresetOperator(AddPresetBase, bpy.types.Operator): +class AddPresetOperator(AddPresetBase, Operator): '''Add an Application Interaction Preset''' bl_idname = "wm.operator_preset_add" bl_label = "Operator Preset" @@ -345,7 +346,7 @@ class AddPresetOperator(AddPresetBase, bpy.types.Operator): @property def preset_values(self): - properties_blacklist = bpy.types.Operator.bl_rna.properties.keys() + properties_blacklist = Operator.bl_rna.properties.keys() prefix, suffix = self.operator.split("_OT_", 1) op = getattr(getattr(bpy.ops, prefix.lower()), suffix) @@ -367,12 +368,12 @@ class AddPresetOperator(AddPresetBase, bpy.types.Operator): return os.path.join("operator", "%s.%s" % (prefix.lower(), suffix)) -class WM_MT_operator_presets(bpy.types.Menu): +class WM_MT_operator_presets(Menu): bl_label = "Operator Presets" def draw(self, context): self.operator = context.space_data.operator.bl_idname - bpy.types.Menu.draw_preset(self, context) + Menu.draw_preset(self, context) @property def preset_subdir(self): diff --git a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py index a38d817d738..c2a09d6a4ae 100644 --- a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py +++ b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py @@ -21,6 +21,7 @@ # Originally written by Matt Ebb import bpy +from bpy.types import Operator import os @@ -64,7 +65,7 @@ def guess_player_path(preset): return player_path -class PlayRenderedAnim(bpy.types.Operator): +class PlayRenderedAnim(Operator): '''Plays back rendered frames/movies using an external player.''' bl_idname = "render.play_rendered_anim" bl_label = "Play Rendered Animation" diff --git a/release/scripts/startup/bl_operators/sequencer.py b/release/scripts/startup/bl_operators/sequencer.py index 16b72406c49..d2f85c8d7c7 100644 --- a/release/scripts/startup/bl_operators/sequencer.py +++ b/release/scripts/startup/bl_operators/sequencer.py @@ -19,11 +19,12 @@ # import bpy +from bpy.types import Operator from bpy.props import IntProperty -class SequencerCrossfadeSounds(bpy.types.Operator): +class SequencerCrossfadeSounds(Operator): '''Do crossfading volume animation of two selected sound strips.''' bl_idname = "sequencer.crossfade_sounds" @@ -74,7 +75,7 @@ class SequencerCrossfadeSounds(bpy.types.Operator): return {'CANCELLED'} -class SequencerCutMulticam(bpy.types.Operator): +class SequencerCutMulticam(Operator): '''Cut multicam strip and select camera.''' bl_idname = "sequencer.cut_multicam" @@ -112,7 +113,7 @@ class SequencerCutMulticam(bpy.types.Operator): return {'FINISHED'} -class SequencerDeinterlaceSelectedMovies(bpy.types.Operator): +class SequencerDeinterlaceSelectedMovies(Operator): '''Deinterlace all selected movie sources.''' bl_idname = "sequencer.deinterlace_selected_movies" diff --git a/release/scripts/startup/bl_operators/uvcalc_follow_active.py b/release/scripts/startup/bl_operators/uvcalc_follow_active.py index 43ca9af59ba..6c258d094e8 100644 --- a/release/scripts/startup/bl_operators/uvcalc_follow_active.py +++ b/release/scripts/startup/bl_operators/uvcalc_follow_active.py @@ -22,6 +22,7 @@ # http://mediawiki.blender.org/index.php/Scripts/Manual/UV_Calculate/Follow_active_quads import bpy +from bpy.types import Operator def extend(obj, operator, EXTEND_MODE): @@ -226,7 +227,7 @@ def main(context, operator): extend(obj, operator, operator.properties.mode) -class FollowActiveQuads(bpy.types.Operator): +class FollowActiveQuads(Operator): '''Follow UVs from active quads along continuous face loops''' bl_idname = "uv.follow_active_quads" bl_label = "Follow Active Quads" diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py index d2371b0316a..6b1c6e1be98 100644 --- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py +++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py @@ -19,6 +19,7 @@ # import bpy +from bpy.types import Operator import mathutils @@ -543,7 +544,7 @@ def unwrap(operator, context, **kwargs): from bpy.props import BoolProperty, FloatProperty, IntProperty -class LightMapPack(bpy.types.Operator): +class LightMapPack(Operator): '''Follow UVs from active quads along continuous face loops''' bl_idname = "uv.lightmap_pack" bl_label = "Lightmap Pack" diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py index 851f33bde11..67c2f5d001b 100644 --- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py +++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py @@ -20,6 +20,7 @@ from mathutils import Matrix, Vector, geometry import bpy +from bpy.types import Operator DEG_TO_RAD = 0.017453292519943295 # pi/180.0 SMALL_NUM = 0.000000001 @@ -1116,7 +1117,7 @@ def main(context, from bpy.props import FloatProperty -class SmartProject(bpy.types.Operator): +class SmartProject(Operator): '''This script projection unwraps the selected faces of a mesh. it operates on all selected mesh objects, and can be used unwrap selected faces, or all faces.''' bl_idname = "uv.smart_project" bl_label = "Smart UV Project" diff --git a/release/scripts/startup/bl_operators/vertexpaint_dirt.py b/release/scripts/startup/bl_operators/vertexpaint_dirt.py index 672db71e361..facde82f812 100644 --- a/release/scripts/startup/bl_operators/vertexpaint_dirt.py +++ b/release/scripts/startup/bl_operators/vertexpaint_dirt.py @@ -142,10 +142,11 @@ def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean, import bpy +from bpy.types import Operator from bpy.props import FloatProperty, IntProperty, BoolProperty -class VertexPaintDirt(bpy.types.Operator): +class VertexPaintDirt(Operator): bl_idname = "paint.vertex_color_dirt" bl_label = "Dirty Vertex Colors" bl_options = {'REGISTER', 'UNDO'} diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index f9327aa6c40..fe75c54e60e 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -19,13 +19,14 @@ # import bpy +from bpy.types import Menu, Operator from bpy.props import StringProperty, BoolProperty, IntProperty, \ FloatProperty, EnumProperty from rna_prop_ui import rna_idprop_ui_prop_get, rna_idprop_ui_prop_clear -class MESH_OT_delete_edgeloop(bpy.types.Operator): +class MESH_OT_delete_edgeloop(Operator): '''Delete an edge loop by merging the faces on each side to a single face loop''' bl_idname = "mesh.delete_edgeloop" bl_label = "Delete Edge Loop" @@ -76,7 +77,7 @@ def execute_context_assign(self, context): return {'FINISHED'} -class BRUSH_OT_active_index_set(bpy.types.Operator): +class BRUSH_OT_active_index_set(Operator): '''Set active sculpt/paint brush from it's number''' bl_idname = "brush.active_index_set" bl_label = "Set Brush Number" @@ -104,7 +105,7 @@ class BRUSH_OT_active_index_set(bpy.types.Operator): return {'CANCELLED'} -class WM_OT_context_set_boolean(bpy.types.Operator): +class WM_OT_context_set_boolean(Operator): '''Set a context value.''' bl_idname = "wm.context_set_boolean" bl_label = "Context Set Boolean" @@ -117,7 +118,7 @@ class WM_OT_context_set_boolean(bpy.types.Operator): execute = execute_context_assign -class WM_OT_context_set_int(bpy.types.Operator): # same as enum +class WM_OT_context_set_int(Operator): # same as enum '''Set a context value.''' bl_idname = "wm.context_set_int" bl_label = "Context Set" @@ -130,7 +131,7 @@ class WM_OT_context_set_int(bpy.types.Operator): # same as enum execute = execute_context_assign -class WM_OT_context_scale_int(bpy.types.Operator): +class WM_OT_context_scale_int(Operator): '''Scale an int context value.''' bl_idname = "wm.context_scale_int" bl_label = "Context Set" @@ -166,7 +167,7 @@ class WM_OT_context_scale_int(bpy.types.Operator): return {'FINISHED'} -class WM_OT_context_set_float(bpy.types.Operator): # same as enum +class WM_OT_context_set_float(Operator): # same as enum '''Set a context value.''' bl_idname = "wm.context_set_float" bl_label = "Context Set Float" @@ -180,7 +181,7 @@ class WM_OT_context_set_float(bpy.types.Operator): # same as enum execute = execute_context_assign -class WM_OT_context_set_string(bpy.types.Operator): # same as enum +class WM_OT_context_set_string(Operator): # same as enum '''Set a context value.''' bl_idname = "wm.context_set_string" bl_label = "Context Set String" @@ -193,7 +194,7 @@ class WM_OT_context_set_string(bpy.types.Operator): # same as enum execute = execute_context_assign -class WM_OT_context_set_enum(bpy.types.Operator): +class WM_OT_context_set_enum(Operator): '''Set a context value.''' bl_idname = "wm.context_set_enum" bl_label = "Context Set Enum" @@ -207,7 +208,7 @@ class WM_OT_context_set_enum(bpy.types.Operator): execute = execute_context_assign -class WM_OT_context_set_value(bpy.types.Operator): +class WM_OT_context_set_value(Operator): '''Set a context value.''' bl_idname = "wm.context_set_value" bl_label = "Context Set Value" @@ -225,7 +226,7 @@ class WM_OT_context_set_value(bpy.types.Operator): return {'FINISHED'} -class WM_OT_context_toggle(bpy.types.Operator): +class WM_OT_context_toggle(Operator): '''Toggle a context value.''' bl_idname = "wm.context_toggle" bl_label = "Context Toggle" @@ -244,7 +245,7 @@ class WM_OT_context_toggle(bpy.types.Operator): return {'FINISHED'} -class WM_OT_context_toggle_enum(bpy.types.Operator): +class WM_OT_context_toggle_enum(Operator): '''Toggle a context value.''' bl_idname = "wm.context_toggle_enum" bl_label = "Context Toggle Values" @@ -270,7 +271,7 @@ class WM_OT_context_toggle_enum(bpy.types.Operator): return {'FINISHED'} -class WM_OT_context_cycle_int(bpy.types.Operator): +class WM_OT_context_cycle_int(Operator): '''Set a context value. Useful for cycling active material, ''' '''vertex keys, groups' etc.''' bl_idname = "wm.context_cycle_int" @@ -305,7 +306,7 @@ class WM_OT_context_cycle_int(bpy.types.Operator): return {'FINISHED'} -class WM_OT_context_cycle_enum(bpy.types.Operator): +class WM_OT_context_cycle_enum(Operator): '''Toggle a context value.''' bl_idname = "wm.context_cycle_enum" bl_label = "Context Enum Cycle" @@ -357,7 +358,7 @@ class WM_OT_context_cycle_enum(bpy.types.Operator): return {'FINISHED'} -class WM_OT_context_cycle_array(bpy.types.Operator): +class WM_OT_context_cycle_array(Operator): '''Set a context array value. Useful for cycling the active mesh edit mode.''' bl_idname = "wm.context_cycle_array" @@ -385,7 +386,7 @@ class WM_OT_context_cycle_array(bpy.types.Operator): return {'FINISHED'} -class WM_MT_context_menu_enum(bpy.types.Menu): +class WM_MT_context_menu_enum(Menu): bl_label = "" data_path = "" # BAD DESIGN, set from operator below. @@ -405,7 +406,7 @@ class WM_MT_context_menu_enum(bpy.types.Menu): prop.value = identifier -class WM_OT_context_menu_enum(bpy.types.Operator): +class WM_OT_context_menu_enum(Operator): bl_idname = "wm.context_menu_enum" bl_label = "Context Enum Menu" bl_options = {'UNDO', 'INTERNAL'} @@ -418,7 +419,7 @@ class WM_OT_context_menu_enum(bpy.types.Operator): return {'PASS_THROUGH'} -class WM_OT_context_set_id(bpy.types.Operator): +class WM_OT_context_set_id(Operator): '''Toggle a context value.''' bl_idname = "wm.context_set_id" bl_label = "Set Library ID" @@ -466,7 +467,7 @@ data_path_item = StringProperty( description="The data path from each iterable to the value (int or float)") -class WM_OT_context_collection_boolean_set(bpy.types.Operator): +class WM_OT_context_collection_boolean_set(Operator): '''Set boolean values for a collection of items''' bl_idname = "wm.context_collection_boolean_set" bl_label = "Context Collection Boolean Set" @@ -520,7 +521,7 @@ class WM_OT_context_collection_boolean_set(bpy.types.Operator): return {'FINISHED'} -class WM_OT_context_modal_mouse(bpy.types.Operator): +class WM_OT_context_modal_mouse(Operator): '''Adjust arbitrary values with mouse input''' bl_idname = "wm.context_modal_mouse" bl_label = "Context Modal Mouse" @@ -607,7 +608,7 @@ class WM_OT_context_modal_mouse(bpy.types.Operator): return {'RUNNING_MODAL'} -class WM_OT_url_open(bpy.types.Operator): +class WM_OT_url_open(Operator): "Open a website in the Webbrowser" bl_idname = "wm.url_open" bl_label = "" @@ -621,7 +622,7 @@ class WM_OT_url_open(bpy.types.Operator): return {'FINISHED'} -class WM_OT_path_open(bpy.types.Operator): +class WM_OT_path_open(Operator): "Open a path in a file browser" bl_idname = "wm.path_open" bl_label = "" @@ -654,7 +655,7 @@ class WM_OT_path_open(bpy.types.Operator): return {'FINISHED'} -class WM_OT_doc_view(bpy.types.Operator): +class WM_OT_doc_view(Operator): '''Load online reference docs''' bl_idname = "wm.doc_view" bl_label = "View Documentation" @@ -708,7 +709,7 @@ class WM_OT_doc_view(bpy.types.Operator): return {'FINISHED'} -class WM_OT_doc_edit(bpy.types.Operator): +class WM_OT_doc_edit(Operator): '''Load online reference docs''' bl_idname = "wm.doc_edit" bl_label = "Edit Documentation" @@ -792,7 +793,7 @@ rna_min = FloatProperty(name="Min", default=0.0, precision=3) rna_max = FloatProperty(name="Max", default=1.0, precision=3) -class WM_OT_properties_edit(bpy.types.Operator): +class WM_OT_properties_edit(Operator): '''Internal use (edit a property data_path)''' bl_idname = "wm.properties_edit" bl_label = "Edit Property" @@ -876,7 +877,7 @@ class WM_OT_properties_edit(bpy.types.Operator): return wm.invoke_props_dialog(self) -class WM_OT_properties_add(bpy.types.Operator): +class WM_OT_properties_add(Operator): '''Internal use (edit a property data_path)''' bl_idname = "wm.properties_add" bl_label = "Add Property" @@ -902,7 +903,7 @@ class WM_OT_properties_add(bpy.types.Operator): return {'FINISHED'} -class WM_OT_properties_context_change(bpy.types.Operator): +class WM_OT_properties_context_change(Operator): "Change the context tab in a Properties Window" bl_idname = "wm.properties_context_change" bl_label = "" @@ -914,7 +915,7 @@ class WM_OT_properties_context_change(bpy.types.Operator): return {'FINISHED'} -class WM_OT_properties_remove(bpy.types.Operator): +class WM_OT_properties_remove(Operator): '''Internal use (edit a property data_path)''' bl_idname = "wm.properties_remove" bl_label = "Remove Property" @@ -928,7 +929,7 @@ class WM_OT_properties_remove(bpy.types.Operator): return {'FINISHED'} -class WM_OT_keyconfig_activate(bpy.types.Operator): +class WM_OT_keyconfig_activate(Operator): bl_idname = "wm.keyconfig_activate" bl_label = "Activate Keyconfig" @@ -939,7 +940,7 @@ class WM_OT_keyconfig_activate(bpy.types.Operator): return {'FINISHED'} -class WM_OT_appconfig_default(bpy.types.Operator): +class WM_OT_appconfig_default(Operator): bl_idname = "wm.appconfig_default" bl_label = "Default Application Configuration" @@ -956,7 +957,7 @@ class WM_OT_appconfig_default(bpy.types.Operator): return {'FINISHED'} -class WM_OT_appconfig_activate(bpy.types.Operator): +class WM_OT_appconfig_activate(Operator): bl_idname = "wm.appconfig_activate" bl_label = "Activate Application Configuration" @@ -974,7 +975,7 @@ class WM_OT_appconfig_activate(bpy.types.Operator): return {'FINISHED'} -class WM_OT_sysinfo(bpy.types.Operator): +class WM_OT_sysinfo(Operator): '''Generate System Info''' bl_idname = "wm.sysinfo" bl_label = "System Info" @@ -985,7 +986,7 @@ class WM_OT_sysinfo(bpy.types.Operator): return {'FINISHED'} -class WM_OT_copy_prev_settings(bpy.types.Operator): +class WM_OT_copy_prev_settings(Operator): '''Copy settings from previous version''' bl_idname = "wm.copy_prev_settings" bl_label = "Copy Previous Settings" diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py index f2a3bac2373..94c40d11141 100644 --- a/release/scripts/startup/bl_ui/properties_data_armature.py +++ b/release/scripts/startup/bl_ui/properties_data_armature.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Panel from rna_prop_ui import PropertyPanel @@ -31,7 +32,7 @@ class ArmatureButtonsPanel(): return context.armature -class DATA_PT_context_arm(ArmatureButtonsPanel, bpy.types.Panel): +class DATA_PT_context_arm(ArmatureButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} @@ -48,7 +49,7 @@ class DATA_PT_context_arm(ArmatureButtonsPanel, bpy.types.Panel): layout.template_ID(space, "pin_id") -class DATA_PT_skeleton(ArmatureButtonsPanel, bpy.types.Panel): +class DATA_PT_skeleton(ArmatureButtonsPanel, Panel): bl_label = "Skeleton" def draw(self, context): @@ -71,7 +72,7 @@ class DATA_PT_skeleton(ArmatureButtonsPanel, bpy.types.Panel): flow.prop(arm, "use_deform_preserve_volume", text="Quaternion") -class DATA_PT_display(ArmatureButtonsPanel, bpy.types.Panel): +class DATA_PT_display(ArmatureButtonsPanel, Panel): bl_label = "Display" def draw(self, context): @@ -96,7 +97,7 @@ class DATA_PT_display(ArmatureButtonsPanel, bpy.types.Panel): col.prop(arm, "use_deform_delay", text="Delay Refresh") -class DATA_PT_bone_groups(ArmatureButtonsPanel, bpy.types.Panel): +class DATA_PT_bone_groups(ArmatureButtonsPanel, Panel): bl_label = "Bone Groups" @classmethod @@ -147,7 +148,7 @@ class DATA_PT_bone_groups(ArmatureButtonsPanel, bpy.types.Panel): sub.operator("pose.group_deselect", text="Deselect") -class DATA_PT_pose_library(ArmatureButtonsPanel, bpy.types.Panel): +class DATA_PT_pose_library(ArmatureButtonsPanel, Panel): bl_label = "Pose Library" bl_options = {'DEFAULT_CLOSED'} @@ -186,7 +187,7 @@ class DATA_PT_pose_library(ArmatureButtonsPanel, bpy.types.Panel): # TODO: this panel will soon be depreceated too -class DATA_PT_ghost(ArmatureButtonsPanel, bpy.types.Panel): +class DATA_PT_ghost(ArmatureButtonsPanel, Panel): bl_label = "Ghost" def draw(self, context): @@ -213,7 +214,7 @@ class DATA_PT_ghost(ArmatureButtonsPanel, bpy.types.Panel): col.prop(arm, "show_only_ghost_selected", text="Selected Only") -class DATA_PT_iksolver_itasc(ArmatureButtonsPanel, bpy.types.Panel): +class DATA_PT_iksolver_itasc(ArmatureButtonsPanel, Panel): bl_label = "iTaSC parameters" bl_options = {'DEFAULT_CLOSED'} @@ -266,7 +267,7 @@ from bl_ui.properties_animviz import ( ) -class DATA_PT_motion_paths(MotionPathButtonsPanel, bpy.types.Panel): +class DATA_PT_motion_paths(MotionPathButtonsPanel, Panel): #bl_label = "Bones Motion Paths" bl_context = "data" @@ -289,7 +290,7 @@ class DATA_PT_motion_paths(MotionPathButtonsPanel, bpy.types.Panel): split.operator("pose.paths_clear", text="Clear Paths") -class DATA_PT_onion_skinning(OnionSkinButtonsPanel): # , bpy.types.Panel): # inherit from panel when ready +class DATA_PT_onion_skinning(OnionSkinButtonsPanel): # , Panel): # inherit from panel when ready #bl_label = "Bones Onion Skinning" bl_context = "data" @@ -303,7 +304,7 @@ class DATA_PT_onion_skinning(OnionSkinButtonsPanel): # , bpy.types.Panel): # in self.draw_settings(context, ob.pose.animation_visualisation, bones=True) -class DATA_PT_custom_props_arm(ArmatureButtonsPanel, PropertyPanel, bpy.types.Panel): +class DATA_PT_custom_props_arm(ArmatureButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} _context_path = "object.data" _property_type = bpy.types.Armature diff --git a/release/scripts/startup/bl_ui/properties_data_bone.py b/release/scripts/startup/bl_ui/properties_data_bone.py index 9fc055e9343..b3eaf88d5bf 100644 --- a/release/scripts/startup/bl_ui/properties_data_bone.py +++ b/release/scripts/startup/bl_ui/properties_data_bone.py @@ -19,6 +19,7 @@ # import bpy +from bpy.types import Panel from rna_prop_ui import PropertyPanel @@ -32,7 +33,7 @@ class BoneButtonsPanel(): return (context.bone or context.edit_bone) -class BONE_PT_context_bone(BoneButtonsPanel, bpy.types.Panel): +class BONE_PT_context_bone(BoneButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} @@ -48,7 +49,7 @@ class BONE_PT_context_bone(BoneButtonsPanel, bpy.types.Panel): row.prop(bone, "name", text="") -class BONE_PT_transform(BoneButtonsPanel, bpy.types.Panel): +class BONE_PT_transform(BoneButtonsPanel, Panel): bl_label = "Transform" @classmethod @@ -102,7 +103,7 @@ class BONE_PT_transform(BoneButtonsPanel, bpy.types.Panel): sub.prop(bone, "lock") -class BONE_PT_transform_locks(BoneButtonsPanel, bpy.types.Panel): +class BONE_PT_transform_locks(BoneButtonsPanel, Panel): bl_label = "Transform Locks" bl_options = {'DEFAULT_CLOSED'} @@ -135,7 +136,7 @@ class BONE_PT_transform_locks(BoneButtonsPanel, bpy.types.Panel): row.column().prop(pchan, "lock_scale") -class BONE_PT_relations(BoneButtonsPanel, bpy.types.Panel): +class BONE_PT_relations(BoneButtonsPanel, Panel): bl_label = "Relations" def draw(self, context): @@ -180,7 +181,7 @@ class BONE_PT_relations(BoneButtonsPanel, bpy.types.Panel): sub.prop(bone, "use_local_location", text="Local Location") -class BONE_PT_display(BoneButtonsPanel, bpy.types.Panel): +class BONE_PT_display(BoneButtonsPanel, Panel): bl_label = "Display" @classmethod @@ -217,7 +218,7 @@ class BONE_PT_display(BoneButtonsPanel, bpy.types.Panel): col.prop_search(pchan, "custom_shape_transform", ob.pose, "bones", text="At") -class BONE_PT_inverse_kinematics(BoneButtonsPanel, bpy.types.Panel): +class BONE_PT_inverse_kinematics(BoneButtonsPanel, Panel): bl_label = "Inverse Kinematics" bl_options = {'DEFAULT_CLOSED'} @@ -308,7 +309,7 @@ class BONE_PT_inverse_kinematics(BoneButtonsPanel, bpy.types.Panel): #row.prop(pchan, "ik_linear_weight", text="Weight", slider=True) -class BONE_PT_deform(BoneButtonsPanel, bpy.types.Panel): +class BONE_PT_deform(BoneButtonsPanel, Panel): bl_label = "Deform" bl_options = {'DEFAULT_CLOSED'} @@ -357,7 +358,7 @@ class BONE_PT_deform(BoneButtonsPanel, bpy.types.Panel): col.prop(bone, "use_cyclic_offset") -class BONE_PT_custom_props(BoneButtonsPanel, PropertyPanel, bpy.types.Panel): +class BONE_PT_custom_props(BoneButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} _property_type = bpy.types.Bone, bpy.types.EditBone, bpy.types.PoseBone diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py index 80cd5227fca..f484d7b59e1 100644 --- a/release/scripts/startup/bl_ui/properties_data_camera.py +++ b/release/scripts/startup/bl_ui/properties_data_camera.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Panel from rna_prop_ui import PropertyPanel @@ -32,7 +33,7 @@ class CameraButtonsPanel(): return context.camera and (engine in cls.COMPAT_ENGINES) -class DATA_PT_context_camera(CameraButtonsPanel, bpy.types.Panel): +class DATA_PT_context_camera(CameraButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -53,7 +54,7 @@ class DATA_PT_context_camera(CameraButtonsPanel, bpy.types.Panel): split.separator() -class DATA_PT_camera(CameraButtonsPanel, bpy.types.Panel): +class DATA_PT_camera(CameraButtonsPanel, Panel): bl_label = "Lens" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -111,7 +112,7 @@ class DATA_PT_camera(CameraButtonsPanel, bpy.types.Panel): col.prop(cam, "dof_distance", text="Distance") -class DATA_PT_camera_display(CameraButtonsPanel, bpy.types.Panel): +class DATA_PT_camera_display(CameraButtonsPanel, Panel): bl_label = "Display" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -138,7 +139,7 @@ class DATA_PT_camera_display(CameraButtonsPanel, bpy.types.Panel): sub.prop(cam, "passepartout_alpha", text="Alpha", slider=True) -class DATA_PT_custom_props_camera(CameraButtonsPanel, PropertyPanel, bpy.types.Panel): +class DATA_PT_custom_props_camera(CameraButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} _context_path = "object.data" _property_type = bpy.types.Camera diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py index a0aacc4cec8..7bc136c8ce0 100644 --- a/release/scripts/startup/bl_ui/properties_data_curve.py +++ b/release/scripts/startup/bl_ui/properties_data_curve.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Panel from rna_prop_ui import PropertyPanel @@ -48,7 +49,7 @@ class CurveButtonsPanelActive(CurveButtonsPanel): return (curve and type(curve) is not bpy.types.TextCurve and curve.splines.active) -class DATA_PT_context_curve(CurveButtonsPanel, bpy.types.Panel): +class DATA_PT_context_curve(CurveButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} @@ -65,7 +66,7 @@ class DATA_PT_context_curve(CurveButtonsPanel, bpy.types.Panel): layout.template_ID(space, "pin_id") # XXX: broken -class DATA_PT_shape_curve(CurveButtonsPanel, bpy.types.Panel): +class DATA_PT_shape_curve(CurveButtonsPanel, Panel): bl_label = "Shape" def draw(self, context): @@ -114,7 +115,7 @@ class DATA_PT_shape_curve(CurveButtonsPanel, bpy.types.Panel): col.prop(curve, "use_fill_deform", text="Fill Deformed") -class DATA_PT_curve_texture_space(CurveButtonsPanel, bpy.types.Panel): +class DATA_PT_curve_texture_space(CurveButtonsPanel, Panel): bl_label = "Texture Space" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -133,7 +134,7 @@ class DATA_PT_curve_texture_space(CurveButtonsPanel, bpy.types.Panel): row.column().prop(curve, "texspace_size", text="Size") -class DATA_PT_geometry_curve(CurveButtonsPanel, bpy.types.Panel): +class DATA_PT_geometry_curve(CurveButtonsPanel, Panel): bl_label = "Geometry" @classmethod @@ -166,7 +167,7 @@ class DATA_PT_geometry_curve(CurveButtonsPanel, bpy.types.Panel): col.prop(curve, "bevel_object", text="") -class DATA_PT_pathanim(CurveButtonsPanelCurve, bpy.types.Panel): +class DATA_PT_pathanim(CurveButtonsPanelCurve, Panel): bl_label = "Path Animation" def draw_header(self, context): @@ -197,7 +198,7 @@ class DATA_PT_pathanim(CurveButtonsPanelCurve, bpy.types.Panel): col.prop(curve, "use_time_offset", text="Offset Children") -class DATA_PT_active_spline(CurveButtonsPanelActive, bpy.types.Panel): +class DATA_PT_active_spline(CurveButtonsPanelActive, Panel): bl_label = "Active Spline" def draw(self, context): @@ -268,7 +269,7 @@ class DATA_PT_active_spline(CurveButtonsPanelActive, bpy.types.Panel): layout.prop(act_spline, "use_smooth") -class DATA_PT_font(CurveButtonsPanel, bpy.types.Panel): +class DATA_PT_font(CurveButtonsPanel, Panel): bl_label = "Font" @classmethod @@ -332,7 +333,7 @@ class DATA_PT_font(CurveButtonsPanel, bpy.types.Panel): row.prop(char, "use_small_caps") -class DATA_PT_paragraph(CurveButtonsPanel, bpy.types.Panel): +class DATA_PT_paragraph(CurveButtonsPanel, Panel): bl_label = "Paragraph" @classmethod @@ -361,7 +362,7 @@ class DATA_PT_paragraph(CurveButtonsPanel, bpy.types.Panel): col.prop(text, "offset_y", text="Y") -class DATA_PT_text_boxes(CurveButtonsPanel, bpy.types.Panel): +class DATA_PT_text_boxes(CurveButtonsPanel, Panel): bl_label = "Text Boxes" @classmethod @@ -401,7 +402,7 @@ class DATA_PT_text_boxes(CurveButtonsPanel, bpy.types.Panel): row.operator("font.textbox_remove", text='', icon='X', emboss=False).index = i -class DATA_PT_custom_props_curve(CurveButtonsPanel, PropertyPanel, bpy.types.Panel): +class DATA_PT_custom_props_curve(CurveButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} _context_path = "object.data" _property_type = bpy.types.Curve diff --git a/release/scripts/startup/bl_ui/properties_data_empty.py b/release/scripts/startup/bl_ui/properties_data_empty.py index 42b0af7eaf5..c781873e16c 100644 --- a/release/scripts/startup/bl_ui/properties_data_empty.py +++ b/release/scripts/startup/bl_ui/properties_data_empty.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Panel class DataButtonsPanel(): @@ -30,7 +31,7 @@ class DataButtonsPanel(): return (context.object and context.object.type == 'EMPTY') -class DATA_PT_empty(DataButtonsPanel, bpy.types.Panel): +class DATA_PT_empty(DataButtonsPanel, Panel): bl_label = "Empty" def draw(self, context): diff --git a/release/scripts/startup/bl_ui/properties_data_lamp.py b/release/scripts/startup/bl_ui/properties_data_lamp.py index 36010c8b511..4ff180f74fb 100644 --- a/release/scripts/startup/bl_ui/properties_data_lamp.py +++ b/release/scripts/startup/bl_ui/properties_data_lamp.py @@ -18,15 +18,16 @@ # import bpy +from bpy.types import Menu, Panel from rna_prop_ui import PropertyPanel -class LAMP_MT_sunsky_presets(bpy.types.Menu): +class LAMP_MT_sunsky_presets(Menu): bl_label = "Sun & Sky Presets" preset_subdir = "sunsky" preset_operator = "script.execute_preset" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - draw = bpy.types.Menu.draw_preset + draw = Menu.draw_preset class DataButtonsPanel(): @@ -40,7 +41,7 @@ class DataButtonsPanel(): return context.lamp and (engine in cls.COMPAT_ENGINES) -class DATA_PT_context_lamp(DataButtonsPanel, bpy.types.Panel): +class DATA_PT_context_lamp(DataButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -65,7 +66,7 @@ class DATA_PT_context_lamp(DataButtonsPanel, bpy.types.Panel): split.label(text=str(texture_count), icon='TEXTURE') -class DATA_PT_preview(DataButtonsPanel, bpy.types.Panel): +class DATA_PT_preview(DataButtonsPanel, Panel): bl_label = "Preview" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -73,7 +74,7 @@ class DATA_PT_preview(DataButtonsPanel, bpy.types.Panel): self.layout.template_preview(context.lamp) -class DATA_PT_lamp(DataButtonsPanel, bpy.types.Panel): +class DATA_PT_lamp(DataButtonsPanel, Panel): bl_label = "Lamp" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -115,7 +116,7 @@ class DATA_PT_lamp(DataButtonsPanel, bpy.types.Panel): col.prop(lamp, "use_diffuse") -class DATA_PT_sunsky(DataButtonsPanel, bpy.types.Panel): +class DATA_PT_sunsky(DataButtonsPanel, Panel): bl_label = "Sky & Atmosphere" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -187,7 +188,7 @@ class DATA_PT_sunsky(DataButtonsPanel, bpy.types.Panel): sub.prop(lamp, "atmosphere_extinction", slider=True, text="Extinction") -class DATA_PT_shadow(DataButtonsPanel, bpy.types.Panel): +class DATA_PT_shadow(DataButtonsPanel, Panel): bl_label = "Shadow" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -302,7 +303,7 @@ class DATA_PT_shadow(DataButtonsPanel, bpy.types.Panel): sub.prop(lamp, "shadow_buffer_clip_end", text=" Clip End") -class DATA_PT_area(DataButtonsPanel, bpy.types.Panel): +class DATA_PT_area(DataButtonsPanel, Panel): bl_label = "Area Shape" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -328,7 +329,7 @@ class DATA_PT_area(DataButtonsPanel, bpy.types.Panel): sub.prop(lamp, "size_y", text="Size Y") -class DATA_PT_spot(DataButtonsPanel, bpy.types.Panel): +class DATA_PT_spot(DataButtonsPanel, Panel): bl_label = "Spot Shape" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -362,7 +363,7 @@ class DATA_PT_spot(DataButtonsPanel, bpy.types.Panel): sub.prop(lamp, "halo_step", text="Step") -class DATA_PT_falloff_curve(DataButtonsPanel, bpy.types.Panel): +class DATA_PT_falloff_curve(DataButtonsPanel, Panel): bl_label = "Falloff Curve" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -380,7 +381,7 @@ class DATA_PT_falloff_curve(DataButtonsPanel, bpy.types.Panel): self.layout.template_curve_mapping(lamp, "falloff_curve") -class DATA_PT_custom_props_lamp(DataButtonsPanel, PropertyPanel, bpy.types.Panel): +class DATA_PT_custom_props_lamp(DataButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} _context_path = "object.data" _property_type = bpy.types.Lamp diff --git a/release/scripts/startup/bl_ui/properties_data_lattice.py b/release/scripts/startup/bl_ui/properties_data_lattice.py index cd719b6fe84..14d6ea66894 100644 --- a/release/scripts/startup/bl_ui/properties_data_lattice.py +++ b/release/scripts/startup/bl_ui/properties_data_lattice.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Panel from rna_prop_ui import PropertyPanel @@ -31,7 +32,7 @@ class DataButtonsPanel(): return context.lattice -class DATA_PT_context_lattice(DataButtonsPanel, bpy.types.Panel): +class DATA_PT_context_lattice(DataButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} @@ -51,7 +52,7 @@ class DATA_PT_context_lattice(DataButtonsPanel, bpy.types.Panel): split.separator() -class DATA_PT_lattice(DataButtonsPanel, bpy.types.Panel): +class DATA_PT_lattice(DataButtonsPanel, Panel): bl_label = "Lattice" def draw(self, context): @@ -76,7 +77,7 @@ class DATA_PT_lattice(DataButtonsPanel, bpy.types.Panel): row.prop_search(lat, "vertex_group", context.object, "vertex_groups", text="") -class DATA_PT_custom_props_lattice(DataButtonsPanel, PropertyPanel, bpy.types.Panel): +class DATA_PT_custom_props_lattice(DataButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} _context_path = "object.data" _property_type = bpy.types.Lattice diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index 618a88f0879..75df7dad5f2 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -18,10 +18,11 @@ # import bpy +from bpy.types import Menu, Panel from rna_prop_ui import PropertyPanel -class MESH_MT_vertex_group_specials(bpy.types.Menu): +class MESH_MT_vertex_group_specials(Menu): bl_label = "Vertex Group Specials" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -36,7 +37,7 @@ class MESH_MT_vertex_group_specials(bpy.types.Menu): layout.operator("object.vertex_group_remove", icon='X', text="Delete All").all = True -class MESH_MT_shape_key_specials(bpy.types.Menu): +class MESH_MT_shape_key_specials(Menu): bl_label = "Shape Key Specials" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -61,7 +62,7 @@ class MeshButtonsPanel(): return context.mesh and (engine in cls.COMPAT_ENGINES) -class DATA_PT_context_mesh(MeshButtonsPanel, bpy.types.Panel): +class DATA_PT_context_mesh(MeshButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -79,7 +80,7 @@ class DATA_PT_context_mesh(MeshButtonsPanel, bpy.types.Panel): layout.template_ID(space, "pin_id") -class DATA_PT_normals(MeshButtonsPanel, bpy.types.Panel): +class DATA_PT_normals(MeshButtonsPanel, Panel): bl_label = "Normals" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -99,7 +100,7 @@ class DATA_PT_normals(MeshButtonsPanel, bpy.types.Panel): split.prop(mesh, "show_double_sided") -class DATA_PT_texture_space(MeshButtonsPanel, bpy.types.Panel): +class DATA_PT_texture_space(MeshButtonsPanel, Panel): bl_label = "Texture Space" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -119,7 +120,7 @@ class DATA_PT_texture_space(MeshButtonsPanel, bpy.types.Panel): row.column().prop(mesh, "texspace_size", text="Size") -class DATA_PT_vertex_groups(MeshButtonsPanel, bpy.types.Panel): +class DATA_PT_vertex_groups(MeshButtonsPanel, Panel): bl_label = "Vertex Groups" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -168,7 +169,7 @@ class DATA_PT_vertex_groups(MeshButtonsPanel, bpy.types.Panel): layout.prop(context.tool_settings, "vertex_group_weight", text="Weight") -class DATA_PT_shape_keys(MeshButtonsPanel, bpy.types.Panel): +class DATA_PT_shape_keys(MeshButtonsPanel, Panel): bl_label = "Shape Keys" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -261,7 +262,7 @@ class DATA_PT_shape_keys(MeshButtonsPanel, bpy.types.Panel): row.prop(key, "slurph") -class DATA_PT_uv_texture(MeshButtonsPanel, bpy.types.Panel): +class DATA_PT_uv_texture(MeshButtonsPanel, Panel): bl_label = "UV Texture" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -284,7 +285,7 @@ class DATA_PT_uv_texture(MeshButtonsPanel, bpy.types.Panel): layout.prop(lay, "name") -class DATA_PT_texface(MeshButtonsPanel, bpy.types.Panel): +class DATA_PT_texface(MeshButtonsPanel, Panel): bl_label = "Texture Face" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -331,7 +332,7 @@ class DATA_PT_texface(MeshButtonsPanel, bpy.types.Panel): col.label(text="No UV Texture") -class DATA_PT_vertex_colors(MeshButtonsPanel, bpy.types.Panel): +class DATA_PT_vertex_colors(MeshButtonsPanel, Panel): bl_label = "Vertex Colors" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -354,7 +355,7 @@ class DATA_PT_vertex_colors(MeshButtonsPanel, bpy.types.Panel): layout.prop(lay, "name") -class DATA_PT_custom_props_mesh(MeshButtonsPanel, PropertyPanel, bpy.types.Panel): +class DATA_PT_custom_props_mesh(MeshButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} _context_path = "object.data" _property_type = bpy.types.Mesh diff --git a/release/scripts/startup/bl_ui/properties_data_metaball.py b/release/scripts/startup/bl_ui/properties_data_metaball.py index 6dda99bc37f..cd894e60dbb 100644 --- a/release/scripts/startup/bl_ui/properties_data_metaball.py +++ b/release/scripts/startup/bl_ui/properties_data_metaball.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Panel from rna_prop_ui import PropertyPanel @@ -31,7 +32,7 @@ class DataButtonsPanel(): return context.meta_ball -class DATA_PT_context_metaball(DataButtonsPanel, bpy.types.Panel): +class DATA_PT_context_metaball(DataButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} @@ -48,7 +49,7 @@ class DATA_PT_context_metaball(DataButtonsPanel, bpy.types.Panel): layout.template_ID(space, "pin_id") -class DATA_PT_metaball(DataButtonsPanel, bpy.types.Panel): +class DATA_PT_metaball(DataButtonsPanel, Panel): bl_label = "Metaball" def draw(self, context): @@ -72,7 +73,7 @@ class DATA_PT_metaball(DataButtonsPanel, bpy.types.Panel): layout.prop(mball, "update_method", expand=True) -class DATA_PT_mball_texture_space(DataButtonsPanel, bpy.types.Panel): +class DATA_PT_mball_texture_space(DataButtonsPanel, Panel): bl_label = "Texture Space" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -89,7 +90,7 @@ class DATA_PT_mball_texture_space(DataButtonsPanel, bpy.types.Panel): row.column().prop(mball, "texspace_size", text="Size") -class DATA_PT_metaball_element(DataButtonsPanel, bpy.types.Panel): +class DATA_PT_metaball_element(DataButtonsPanel, Panel): bl_label = "Active Element" @classmethod @@ -129,7 +130,7 @@ class DATA_PT_metaball_element(DataButtonsPanel, bpy.types.Panel): col.prop(metaelem, "size_y", text="Y") -class DATA_PT_custom_props_metaball(DataButtonsPanel, PropertyPanel, bpy.types.Panel): +class DATA_PT_custom_props_metaball(DataButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} _context_path = "object.data" _property_type = bpy.types.MetaBall diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 0a4d0b60514..e4bbd7d7d7d 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Panel class ModifierButtonsPanel(): @@ -26,7 +27,7 @@ class ModifierButtonsPanel(): bl_context = "modifier" -class DATA_PT_modifiers(ModifierButtonsPanel, bpy.types.Panel): +class DATA_PT_modifiers(ModifierButtonsPanel, Panel): bl_label = "Modifiers" def draw(self, context): diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py index 0c07451b3b2..f8be32e6c07 100644 --- a/release/scripts/startup/bl_ui/properties_game.py +++ b/release/scripts/startup/bl_ui/properties_game.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Panel class PhysicsButtonsPanel(): @@ -26,7 +27,7 @@ class PhysicsButtonsPanel(): bl_context = "physics" -class PHYSICS_PT_game_physics(PhysicsButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel): bl_label = "Physics" COMPAT_ENGINES = {'BLENDER_GAME'} @@ -167,7 +168,7 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel, bpy.types.Panel): layout.prop(ob, "hide_render", text="Invisible") -class PHYSICS_PT_game_collision_bounds(PhysicsButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_game_collision_bounds(PhysicsButtonsPanel, Panel): bl_label = "Collision Bounds" COMPAT_ENGINES = {'BLENDER_GAME'} @@ -206,7 +207,7 @@ class RenderButtonsPanel(): return (rd.engine in cls.COMPAT_ENGINES) -class RENDER_PT_game(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_game(RenderButtonsPanel, Panel): bl_label = "Game" COMPAT_ENGINES = {'BLENDER_GAME'} @@ -218,7 +219,7 @@ class RENDER_PT_game(RenderButtonsPanel, bpy.types.Panel): row.label() -class RENDER_PT_game_player(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_game_player(RenderButtonsPanel, Panel): bl_label = "Standalone Player" COMPAT_ENGINES = {'BLENDER_GAME'} @@ -251,7 +252,7 @@ class RENDER_PT_game_player(RenderButtonsPanel, bpy.types.Panel): col.prop(gs, "frame_color", text="") -class RENDER_PT_game_stereo(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_game_stereo(RenderButtonsPanel, Panel): bl_label = "Stereo" COMPAT_ENGINES = {'BLENDER_GAME'} @@ -305,7 +306,7 @@ class RENDER_PT_game_stereo(RenderButtonsPanel, bpy.types.Panel): layout.prop(gs, "dome_text") -class RENDER_PT_game_shading(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_game_shading(RenderButtonsPanel, Panel): bl_label = "Shading" COMPAT_ENGINES = {'BLENDER_GAME'} @@ -331,7 +332,7 @@ class RENDER_PT_game_shading(RenderButtonsPanel, bpy.types.Panel): col.prop(gs, "use_glsl_extra_textures", text="Extra Textures") -class RENDER_PT_game_performance(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_game_performance(RenderButtonsPanel, Panel): bl_label = "Performance" COMPAT_ENGINES = {'BLENDER_GAME'} @@ -344,7 +345,7 @@ class RENDER_PT_game_performance(RenderButtonsPanel, bpy.types.Panel): row.prop(gs, "use_display_lists") -class RENDER_PT_game_display(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_game_display(RenderButtonsPanel, Panel): bl_label = "Display" COMPAT_ENGINES = {'BLENDER_GAME'} @@ -360,7 +361,7 @@ class RENDER_PT_game_display(RenderButtonsPanel, bpy.types.Panel): flow.prop(gs, "show_mouse", text="Mouse Cursor") -class RENDER_PT_game_sound(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_game_sound(RenderButtonsPanel, Panel): bl_label = "Sound" COMPAT_ENGINES = {'BLENDER_GAME'} @@ -381,7 +382,7 @@ class WorldButtonsPanel(): bl_context = "world" -class WORLD_PT_game_context_world(WorldButtonsPanel, bpy.types.Panel): +class WORLD_PT_game_context_world(WorldButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} COMPAT_ENGINES = {'BLENDER_GAME'} @@ -405,7 +406,7 @@ class WORLD_PT_game_context_world(WorldButtonsPanel, bpy.types.Panel): split.template_ID(space, "pin_id") -class WORLD_PT_game_world(WorldButtonsPanel, bpy.types.Panel): +class WORLD_PT_game_world(WorldButtonsPanel, Panel): bl_label = "World" COMPAT_ENGINES = {'BLENDER_GAME'} @@ -424,7 +425,7 @@ class WORLD_PT_game_world(WorldButtonsPanel, bpy.types.Panel): row.column().prop(world, "ambient_color") -class WORLD_PT_game_mist(WorldButtonsPanel, bpy.types.Panel): +class WORLD_PT_game_mist(WorldButtonsPanel, Panel): bl_label = "Mist" COMPAT_ENGINES = {'BLENDER_GAME'} @@ -450,7 +451,7 @@ class WORLD_PT_game_mist(WorldButtonsPanel, bpy.types.Panel): row.prop(world.mist_settings, "depth") -class WORLD_PT_game_physics(WorldButtonsPanel, bpy.types.Panel): +class WORLD_PT_game_physics(WorldButtonsPanel, Panel): bl_label = "Physics" COMPAT_ENGINES = {'BLENDER_GAME'} diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py index 296c05d78f5..13ce92f084c 100644 --- a/release/scripts/startup/bl_ui/properties_material.py +++ b/release/scripts/startup/bl_ui/properties_material.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Menu, Panel from rna_prop_ui import PropertyPanel @@ -50,14 +51,14 @@ def simple_material(mat): return False -class MATERIAL_MT_sss_presets(bpy.types.Menu): +class MATERIAL_MT_sss_presets(Menu): bl_label = "SSS Presets" preset_subdir = "sss" preset_operator = "script.execute_preset" - draw = bpy.types.Menu.draw_preset + draw = Menu.draw_preset -class MATERIAL_MT_specials(bpy.types.Menu): +class MATERIAL_MT_specials(Menu): bl_label = "Material Specials" def draw(self, context): @@ -79,7 +80,7 @@ class MaterialButtonsPanel(): return context.material and (context.scene.render.engine in cls.COMPAT_ENGINES) -class MATERIAL_PT_context_material(MaterialButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_context_material(MaterialButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -144,7 +145,7 @@ class MATERIAL_PT_context_material(MaterialButtonsPanel, bpy.types.Panel): row.label(text="No material node selected") -class MATERIAL_PT_preview(MaterialButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_preview(MaterialButtonsPanel, Panel): bl_label = "Preview" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -152,7 +153,7 @@ class MATERIAL_PT_preview(MaterialButtonsPanel, bpy.types.Panel): self.layout.template_preview(context.material) -class MATERIAL_PT_pipeline(MaterialButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_pipeline(MaterialButtonsPanel, Panel): bl_label = "Render Pipeline Options" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -203,7 +204,7 @@ class MATERIAL_PT_pipeline(MaterialButtonsPanel, bpy.types.Panel): col.prop(mat, "pass_index") -class MATERIAL_PT_diffuse(MaterialButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_diffuse(MaterialButtonsPanel, Panel): bl_label = "Diffuse" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -260,7 +261,7 @@ class MATERIAL_PT_diffuse(MaterialButtonsPanel, bpy.types.Panel): col.prop(mat, "diffuse_ramp_factor", text="Factor") -class MATERIAL_PT_specular(MaterialButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_specular(MaterialButtonsPanel, Panel): bl_label = "Specular" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -313,7 +314,7 @@ class MATERIAL_PT_specular(MaterialButtonsPanel, bpy.types.Panel): layout.prop(mat, "specular_ramp_factor", text="Factor") -class MATERIAL_PT_shading(MaterialButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_shading(MaterialButtonsPanel, Panel): bl_label = "Shading" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -347,7 +348,7 @@ class MATERIAL_PT_shading(MaterialButtonsPanel, bpy.types.Panel): sub.prop(mat, "use_cubic") -class MATERIAL_PT_transp(MaterialButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_transp(MaterialButtonsPanel, Panel): bl_label = "Transparency" # bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -413,7 +414,7 @@ class MATERIAL_PT_transp(MaterialButtonsPanel, bpy.types.Panel): sub.prop(rayt, "gloss_samples", text="Samples") -class MATERIAL_PT_mirror(MaterialButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_mirror(MaterialButtonsPanel, Panel): bl_label = "Mirror" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -471,7 +472,7 @@ class MATERIAL_PT_mirror(MaterialButtonsPanel, bpy.types.Panel): sub.prop(raym, "gloss_anisotropic", text="Anisotropic") -class MATERIAL_PT_sss(MaterialButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_sss(MaterialButtonsPanel, Panel): bl_label = "Subsurface Scattering" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -523,7 +524,7 @@ class MATERIAL_PT_sss(MaterialButtonsPanel, bpy.types.Panel): col.prop(sss, "error_threshold", text="Error") -class MATERIAL_PT_halo(MaterialButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_halo(MaterialButtonsPanel, Panel): bl_label = "Halo" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -576,7 +577,7 @@ class MATERIAL_PT_halo(MaterialButtonsPanel, bpy.types.Panel): number_but(col, "use_star", "star_tip_count", "Star tips", "") -class MATERIAL_PT_flare(MaterialButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_flare(MaterialButtonsPanel, Panel): bl_label = "Flare" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -611,7 +612,7 @@ class MATERIAL_PT_flare(MaterialButtonsPanel, bpy.types.Panel): col.prop(halo, "flare_subflare_size", text="Subsize") -class MATERIAL_PT_physics(MaterialButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_physics(MaterialButtonsPanel, Panel): bl_label = "Physics" COMPAT_ENGINES = {'BLENDER_GAME'} @@ -641,7 +642,7 @@ class MATERIAL_PT_physics(MaterialButtonsPanel, bpy.types.Panel): row.prop(phys, "use_fh_normal") -class MATERIAL_PT_strand(MaterialButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_strand(MaterialButtonsPanel, Panel): bl_label = "Strand" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -688,7 +689,7 @@ class MATERIAL_PT_strand(MaterialButtonsPanel, bpy.types.Panel): sub.prop(tan, "blend_distance", text="Distance") -class MATERIAL_PT_options(MaterialButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_options(MaterialButtonsPanel, Panel): bl_label = "Options" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -737,7 +738,7 @@ class MATERIAL_PT_options(MaterialButtonsPanel, bpy.types.Panel): col.prop(mat, "pass_index") -class MATERIAL_PT_shadow(MaterialButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_shadow(MaterialButtonsPanel, Panel): bl_label = "Shadow" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -781,7 +782,7 @@ class MATERIAL_PT_shadow(MaterialButtonsPanel, bpy.types.Panel): col.prop(mat, "use_cast_approximate") -class MATERIAL_PT_transp_game(MaterialButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_transp_game(MaterialButtonsPanel, Panel): bl_label = "Transparency" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_GAME'} @@ -824,7 +825,7 @@ class VolumeButtonsPanel(): return mat and (mat.type == 'VOLUME') and (engine in cls.COMPAT_ENGINES) -class MATERIAL_PT_volume_density(VolumeButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_volume_density(VolumeButtonsPanel, Panel): bl_label = "Density" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -838,7 +839,7 @@ class MATERIAL_PT_volume_density(VolumeButtonsPanel, bpy.types.Panel): row.prop(vol, "density_scale") -class MATERIAL_PT_volume_shading(VolumeButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_volume_shading(VolumeButtonsPanel, Panel): bl_label = "Shading" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -863,7 +864,7 @@ class MATERIAL_PT_volume_shading(VolumeButtonsPanel, bpy.types.Panel): sub.prop(vol, "reflection_color", text="") -class MATERIAL_PT_volume_lighting(VolumeButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_volume_lighting(VolumeButtonsPanel, Panel): bl_label = "Lighting" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -898,7 +899,7 @@ class MATERIAL_PT_volume_lighting(VolumeButtonsPanel, bpy.types.Panel): sub.prop(vol, "ms_intensity") -class MATERIAL_PT_volume_transp(VolumeButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_volume_transp(VolumeButtonsPanel, Panel): bl_label = "Transparency" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -916,7 +917,7 @@ class MATERIAL_PT_volume_transp(VolumeButtonsPanel, bpy.types.Panel): layout.prop(mat, "transparency_method", expand=True) -class MATERIAL_PT_volume_integration(VolumeButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_volume_integration(VolumeButtonsPanel, Panel): bl_label = "Integration" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -938,7 +939,7 @@ class MATERIAL_PT_volume_integration(VolumeButtonsPanel, bpy.types.Panel): col.prop(vol, "depth_threshold") -class MATERIAL_PT_volume_options(VolumeButtonsPanel, bpy.types.Panel): +class MATERIAL_PT_volume_options(VolumeButtonsPanel, Panel): bl_label = "Options" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} bl_options = {'DEFAULT_CLOSED'} @@ -970,7 +971,7 @@ class MATERIAL_PT_volume_options(VolumeButtonsPanel, bpy.types.Panel): row.prop(mat, "use_light_group_exclusive", text="Exclusive") -class MATERIAL_PT_custom_props(MaterialButtonsPanel, PropertyPanel, bpy.types.Panel): +class MATERIAL_PT_custom_props(MaterialButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} _context_path = "material" _property_type = bpy.types.Material diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py index cdbcf2cf533..0779debb102 100644 --- a/release/scripts/startup/bl_ui/properties_object.py +++ b/release/scripts/startup/bl_ui/properties_object.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Panel from rna_prop_ui import PropertyPanel @@ -27,7 +28,7 @@ class ObjectButtonsPanel(): bl_context = "object" -class OBJECT_PT_context_object(ObjectButtonsPanel, bpy.types.Panel): +class OBJECT_PT_context_object(ObjectButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} @@ -42,7 +43,7 @@ class OBJECT_PT_context_object(ObjectButtonsPanel, bpy.types.Panel): row.template_ID(context.scene.objects, "active") -class OBJECT_PT_transform(ObjectButtonsPanel, bpy.types.Panel): +class OBJECT_PT_transform(ObjectButtonsPanel, Panel): bl_label = "Transform" def draw(self, context): @@ -68,7 +69,7 @@ class OBJECT_PT_transform(ObjectButtonsPanel, bpy.types.Panel): layout.prop(ob, "rotation_mode") -class OBJECT_PT_delta_transform(ObjectButtonsPanel, bpy.types.Panel): +class OBJECT_PT_delta_transform(ObjectButtonsPanel, Panel): bl_label = "Delta Transform" bl_options = {'DEFAULT_CLOSED'} @@ -94,7 +95,7 @@ class OBJECT_PT_delta_transform(ObjectButtonsPanel, bpy.types.Panel): row.column().prop(ob, "delta_scale") -class OBJECT_PT_transform_locks(ObjectButtonsPanel, bpy.types.Panel): +class OBJECT_PT_transform_locks(ObjectButtonsPanel, Panel): bl_label = "Transform Locks" bl_options = {'DEFAULT_CLOSED'} @@ -120,7 +121,7 @@ class OBJECT_PT_transform_locks(ObjectButtonsPanel, bpy.types.Panel): row.column().prop(ob, "lock_scale", text="Scale") -class OBJECT_PT_relations(ObjectButtonsPanel, bpy.types.Panel): +class OBJECT_PT_relations(ObjectButtonsPanel, Panel): bl_label = "Relations" def draw(self, context): @@ -147,7 +148,7 @@ class OBJECT_PT_relations(ObjectButtonsPanel, bpy.types.Panel): sub.active = (parent is not None) -class OBJECT_PT_groups(ObjectButtonsPanel, bpy.types.Panel): +class OBJECT_PT_groups(ObjectButtonsPanel, Panel): bl_label = "Groups" def draw(self, context): @@ -186,7 +187,7 @@ class OBJECT_PT_groups(ObjectButtonsPanel, bpy.types.Panel): index += 1 -class OBJECT_PT_display(ObjectButtonsPanel, bpy.types.Panel): +class OBJECT_PT_display(ObjectButtonsPanel, Panel): bl_label = "Display" def draw(self, context): @@ -220,7 +221,7 @@ class OBJECT_PT_display(ObjectButtonsPanel, bpy.types.Panel): col.prop(ob, "show_transparent", text="Transparency") -class OBJECT_PT_duplication(ObjectButtonsPanel, bpy.types.Panel): +class OBJECT_PT_duplication(ObjectButtonsPanel, Panel): bl_label = "Duplication" def draw(self, context): @@ -258,7 +259,7 @@ class OBJECT_PT_duplication(ObjectButtonsPanel, bpy.types.Panel): # XXX: the following options are all quite buggy, ancient hacks that should be dropped -class OBJECT_PT_animation(ObjectButtonsPanel, bpy.types.Panel): +class OBJECT_PT_animation(ObjectButtonsPanel, Panel): bl_label = "Animation Hacks" bl_options = {'DEFAULT_CLOSED'} @@ -293,7 +294,7 @@ from bl_ui.properties_animviz import ( ) -class OBJECT_PT_motion_paths(MotionPathButtonsPanel, bpy.types.Panel): +class OBJECT_PT_motion_paths(MotionPathButtonsPanel, Panel): #bl_label = "Object Motion Paths" bl_context = "object" @@ -315,7 +316,7 @@ class OBJECT_PT_motion_paths(MotionPathButtonsPanel, bpy.types.Panel): row.operator("object.paths_clear", text="Clear Paths") -class OBJECT_PT_onion_skinning(OnionSkinButtonsPanel): # , bpy.types.Panel): # inherit from panel when ready +class OBJECT_PT_onion_skinning(OnionSkinButtonsPanel): # , Panel): # inherit from panel when ready #bl_label = "Object Onion Skinning" bl_context = "object" @@ -329,7 +330,7 @@ class OBJECT_PT_onion_skinning(OnionSkinButtonsPanel): # , bpy.types.Panel): # self.draw_settings(context, ob.animation_visualisation) -class OBJECT_PT_custom_props(ObjectButtonsPanel, PropertyPanel, bpy.types.Panel): +class OBJECT_PT_custom_props(ObjectButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} _context_path = "object" _property_type = bpy.types.Object diff --git a/release/scripts/startup/bl_ui/properties_object_constraint.py b/release/scripts/startup/bl_ui/properties_object_constraint.py index 5f79dd3127a..867abe4dd5d 100644 --- a/release/scripts/startup/bl_ui/properties_object_constraint.py +++ b/release/scripts/startup/bl_ui/properties_object_constraint.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Panel class ConstraintButtonsPanel(): @@ -755,7 +756,7 @@ class ConstraintButtonsPanel(): layout.label("Blender 2.5 has no py-constraints") -class OBJECT_PT_constraints(ConstraintButtonsPanel, bpy.types.Panel): +class OBJECT_PT_constraints(ConstraintButtonsPanel, Panel): bl_label = "Object Constraints" bl_context = "constraint" @@ -779,7 +780,7 @@ class OBJECT_PT_constraints(ConstraintButtonsPanel, bpy.types.Panel): self.draw_constraint(context, con) -class BONE_PT_constraints(ConstraintButtonsPanel, bpy.types.Panel): +class BONE_PT_constraints(ConstraintButtonsPanel, Panel): bl_label = "Bone Constraints" bl_context = "bone_constraint" diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py index 2870aab75ef..03243d1153b 100644 --- a/release/scripts/startup/bl_ui/properties_particle.py +++ b/release/scripts/startup/bl_ui/properties_particle.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Panel from rna_prop_ui import PropertyPanel from bl_ui.properties_physics_common import ( @@ -72,7 +73,7 @@ class ParticleButtonsPanel(): return particle_panel_poll(cls, context) -class PARTICLE_PT_context_particles(ParticleButtonsPanel, bpy.types.Panel): +class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -176,7 +177,7 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, bpy.types.Panel): split.prop(psys, "reactor_target_particle_system", text="Particle System") -class PARTICLE_PT_emission(ParticleButtonsPanel, bpy.types.Panel): +class PARTICLE_PT_emission(ParticleButtonsPanel, Panel): bl_label = "Emission" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -245,7 +246,7 @@ class PARTICLE_PT_emission(ParticleButtonsPanel, bpy.types.Panel): row.prop(part, "grid_random", text="Random", slider=True) -class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, bpy.types.Panel): +class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, Panel): bl_label = "Hair dynamics" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -301,7 +302,7 @@ class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, bpy.types.Panel): col.prop(cloth, "quality", text="Steps", slider=True) -class PARTICLE_PT_cache(ParticleButtonsPanel, bpy.types.Panel): +class PARTICLE_PT_cache(ParticleButtonsPanel, Panel): bl_label = "Cache" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -327,7 +328,7 @@ class PARTICLE_PT_cache(ParticleButtonsPanel, bpy.types.Panel): point_cache_ui(self, context, psys.point_cache, True, 'HAIR' if (psys.settings.type == 'HAIR') else 'PSYS') -class PARTICLE_PT_velocity(ParticleButtonsPanel, bpy.types.Panel): +class PARTICLE_PT_velocity(ParticleButtonsPanel, Panel): bl_label = "Velocity" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -377,7 +378,7 @@ class PARTICLE_PT_velocity(ParticleButtonsPanel, bpy.types.Panel): # sub.prop(part, "reaction_shape", slider=True) -class PARTICLE_PT_rotation(ParticleButtonsPanel, bpy.types.Panel): +class PARTICLE_PT_rotation(ParticleButtonsPanel, Panel): bl_label = "Rotation" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -426,7 +427,7 @@ class PARTICLE_PT_rotation(ParticleButtonsPanel, bpy.types.Panel): col.prop(part, "angular_velocity_factor", text="") -class PARTICLE_PT_physics(ParticleButtonsPanel, bpy.types.Panel): +class PARTICLE_PT_physics(ParticleButtonsPanel, Panel): bl_label = "Physics" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -641,7 +642,7 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, bpy.types.Panel): sub.prop(key, "system", text="System") -class PARTICLE_PT_boidbrain(ParticleButtonsPanel, bpy.types.Panel): +class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel): bl_label = "Boid Brain" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -742,7 +743,7 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, bpy.types.Panel): row.prop(rule, "flee_distance") -class PARTICLE_PT_render(ParticleButtonsPanel, bpy.types.Panel): +class PARTICLE_PT_render(ParticleButtonsPanel, Panel): bl_label = "Render" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -927,7 +928,7 @@ class PARTICLE_PT_render(ParticleButtonsPanel, bpy.types.Panel): row.prop(part, "size_random", slider=True) -class PARTICLE_PT_draw(ParticleButtonsPanel, bpy.types.Panel): +class PARTICLE_PT_draw(ParticleButtonsPanel, Panel): bl_label = "Display" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -989,7 +990,7 @@ class PARTICLE_PT_draw(ParticleButtonsPanel, bpy.types.Panel): col.prop(part, "draw_step") -class PARTICLE_PT_children(ParticleButtonsPanel, bpy.types.Panel): +class PARTICLE_PT_children(ParticleButtonsPanel, Panel): bl_label = "Children" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -1089,7 +1090,7 @@ class PARTICLE_PT_children(ParticleButtonsPanel, bpy.types.Panel): sub.prop(part, "kink_shape", slider=True) -class PARTICLE_PT_field_weights(ParticleButtonsPanel, bpy.types.Panel): +class PARTICLE_PT_field_weights(ParticleButtonsPanel, Panel): bl_label = "Field Weights" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -1110,7 +1111,7 @@ class PARTICLE_PT_field_weights(ParticleButtonsPanel, bpy.types.Panel): row.prop(part, "effect_hair", slider=True) -class PARTICLE_PT_force_fields(ParticleButtonsPanel, bpy.types.Panel): +class PARTICLE_PT_force_fields(ParticleButtonsPanel, Panel): bl_label = "Force Field Settings" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -1144,7 +1145,7 @@ class PARTICLE_PT_force_fields(ParticleButtonsPanel, bpy.types.Panel): basic_force_field_falloff_ui(self, context, part.force_field_2) -class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, bpy.types.Panel): +class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, Panel): bl_label = "Vertexgroups" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -1215,7 +1216,7 @@ class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, bpy.types.Panel): # row.prop(psys, "invert_vertex_group_field", text="") -class PARTICLE_PT_custom_props(ParticleButtonsPanel, PropertyPanel, bpy.types.Panel): +class PARTICLE_PT_custom_props(ParticleButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER'} _context_path = "particle_system.settings" _property_type = bpy.types.ParticleSettings diff --git a/release/scripts/startup/bl_ui/properties_physics_cloth.py b/release/scripts/startup/bl_ui/properties_physics_cloth.py index bce6ab993a7..d5427d8bae8 100644 --- a/release/scripts/startup/bl_ui/properties_physics_cloth.py +++ b/release/scripts/startup/bl_ui/properties_physics_cloth.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Menu, Panel from bl_ui.properties_physics_common import ( @@ -30,14 +31,14 @@ def cloth_panel_enabled(md): return md.point_cache.is_baked is False -class CLOTH_MT_presets(bpy.types.Menu): +class CLOTH_MT_presets(Menu): ''' Creates the menu items by scanning scripts/templates ''' bl_label = "Cloth Presets" preset_subdir = "cloth" preset_operator = "script.execute_preset" - draw = bpy.types.Menu.draw_preset + draw = Menu.draw_preset class PhysicButtonsPanel(): @@ -52,7 +53,7 @@ class PhysicButtonsPanel(): return (ob and ob.type == 'MESH') and (not rd.use_game_engine) and (context.cloth) -class PHYSICS_PT_cloth(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_cloth(PhysicButtonsPanel, Panel): bl_label = "Cloth" def draw(self, context): @@ -117,7 +118,7 @@ class PHYSICS_PT_cloth(PhysicButtonsPanel, bpy.types.Panel): col.prop_search(cloth, "rest_shape_key", key, "key_blocks", text="") -class PHYSICS_PT_cloth_cache(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_cloth_cache(PhysicButtonsPanel, Panel): bl_label = "Cloth Cache" bl_options = {'DEFAULT_CLOSED'} @@ -130,7 +131,7 @@ class PHYSICS_PT_cloth_cache(PhysicButtonsPanel, bpy.types.Panel): point_cache_ui(self, context, md.point_cache, cloth_panel_enabled(md), 'CLOTH') -class PHYSICS_PT_cloth_collision(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_cloth_collision(PhysicButtonsPanel, Panel): bl_label = "Cloth Collision" bl_options = {'DEFAULT_CLOSED'} @@ -171,7 +172,7 @@ class PHYSICS_PT_cloth_collision(PhysicButtonsPanel, bpy.types.Panel): layout.prop(cloth, "group") -class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel, Panel): bl_label = "Cloth Stiffness Scaling" bl_options = {'DEFAULT_CLOSED'} @@ -207,7 +208,7 @@ class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel, bpy.types.Panel): col.prop(cloth, "bending_stiffness_max", text="Max") -class PHYSICS_PT_cloth_field_weights(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_cloth_field_weights(PhysicButtonsPanel, Panel): bl_label = "Cloth Field Weights" bl_options = {'DEFAULT_CLOSED'} diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py index f7cf8da1840..204e25d9f01 100644 --- a/release/scripts/startup/bl_ui/properties_physics_common.py +++ b/release/scripts/startup/bl_ui/properties_physics_common.py @@ -19,6 +19,7 @@ # import bpy +from bpy.types import Panel class PhysicButtonsPanel(): @@ -44,7 +45,7 @@ def physics_add(self, layout, md, name, type, typeicon, toggles): sub.operator("object.modifier_add", text=name, icon=typeicon).type = type -class PHYSICS_PT_add(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_add(PhysicButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} diff --git a/release/scripts/startup/bl_ui/properties_physics_field.py b/release/scripts/startup/bl_ui/properties_physics_field.py index 9f96f0a5b9f..e1dc4d04378 100644 --- a/release/scripts/startup/bl_ui/properties_physics_field.py +++ b/release/scripts/startup/bl_ui/properties_physics_field.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Panel from bl_ui.properties_physics_common import ( @@ -37,7 +38,7 @@ class PhysicButtonsPanel(): return (context.object) and (not rd.use_game_engine) -class PHYSICS_PT_field(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_field(PhysicButtonsPanel, Panel): bl_label = "Force Fields" @classmethod @@ -164,7 +165,7 @@ class PHYSICS_PT_field(PhysicButtonsPanel, bpy.types.Panel): sub.prop(field, "radial_max", text="Distance") -class PHYSICS_PT_collision(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_collision(PhysicButtonsPanel, Panel): bl_label = "Collision" #bl_options = {'DEFAULT_CLOSED'} diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py index c7e3a9e7220..46893af3582 100644 --- a/release/scripts/startup/bl_ui/properties_physics_fluid.py +++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Panel class PhysicButtonsPanel(): @@ -32,7 +33,7 @@ class PhysicButtonsPanel(): return (ob and ob.type == 'MESH') and (not rd.use_game_engine) and (context.fluid) -class PHYSICS_PT_fluid(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_fluid(PhysicButtonsPanel, Panel): bl_label = "Fluid" def draw(self, context): @@ -186,7 +187,7 @@ class PHYSICS_PT_fluid(PhysicButtonsPanel, bpy.types.Panel): sub.prop(fluid, "velocity_radius", text="Radius") -class PHYSICS_PT_domain_gravity(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_domain_gravity(PhysicButtonsPanel, Panel): bl_label = "Domain World" bl_options = {'DEFAULT_CLOSED'} @@ -236,7 +237,7 @@ class PHYSICS_PT_domain_gravity(PhysicButtonsPanel, bpy.types.Panel): col.prop(fluid, "compressibility", slider=True) -class PHYSICS_PT_domain_boundary(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_domain_boundary(PhysicButtonsPanel, Panel): bl_label = "Domain Boundary" bl_options = {'DEFAULT_CLOSED'} @@ -265,7 +266,7 @@ class PHYSICS_PT_domain_boundary(PhysicButtonsPanel, bpy.types.Panel): col.prop(fluid, "surface_subdivisions", text="Subdivisions") -class PHYSICS_PT_domain_particles(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_domain_particles(PhysicButtonsPanel, Panel): bl_label = "Domain Particles" bl_options = {'DEFAULT_CLOSED'} diff --git a/release/scripts/startup/bl_ui/properties_physics_smoke.py b/release/scripts/startup/bl_ui/properties_physics_smoke.py index 61d8d2e3825..771a778380d 100644 --- a/release/scripts/startup/bl_ui/properties_physics_smoke.py +++ b/release/scripts/startup/bl_ui/properties_physics_smoke.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Panel from bl_ui.properties_physics_common import ( @@ -38,7 +39,7 @@ class PhysicButtonsPanel(): return (ob and ob.type == 'MESH') and (not rd.use_game_engine) and (context.smoke) -class PHYSICS_PT_smoke(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel): bl_label = "Smoke" def draw(self, context): @@ -103,7 +104,7 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, bpy.types.Panel): sub.prop(flow, "temperature") -class PHYSICS_PT_smoke_groups(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_smoke_groups(PhysicButtonsPanel, Panel): bl_label = "Smoke Groups" bl_options = {'DEFAULT_CLOSED'} @@ -131,7 +132,7 @@ class PHYSICS_PT_smoke_groups(PhysicButtonsPanel, bpy.types.Panel): col.prop(group, "collision_group", text="") -class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, Panel): bl_label = "Smoke High Resolution" bl_options = {'DEFAULT_CLOSED'} @@ -168,7 +169,7 @@ class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, bpy.types.Panel): layout.prop(md, "show_high_resolution") -class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel): bl_label = "Smoke Cache" bl_options = {'DEFAULT_CLOSED'} @@ -189,7 +190,7 @@ class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, bpy.types.Panel): point_cache_ui(self, context, cache, (cache.is_baked is False), 'SMOKE') -class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel, Panel): bl_label = "Smoke Field Weights" bl_options = {'DEFAULT_CLOSED'} diff --git a/release/scripts/startup/bl_ui/properties_physics_softbody.py b/release/scripts/startup/bl_ui/properties_physics_softbody.py index 61115a0590e..0b55ccf9516 100644 --- a/release/scripts/startup/bl_ui/properties_physics_softbody.py +++ b/release/scripts/startup/bl_ui/properties_physics_softbody.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Panel from bl_ui.properties_physics_common import ( @@ -44,7 +45,7 @@ class PhysicButtonsPanel(): return (ob and (ob.type == 'MESH' or ob.type == 'LATTICE'or ob.type == 'CURVE')) and (not rd.use_game_engine) and (context.soft_body) -class PHYSICS_PT_softbody(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_softbody(PhysicButtonsPanel, Panel): bl_label = "Soft Body" def draw(self, context): @@ -71,7 +72,7 @@ class PHYSICS_PT_softbody(PhysicButtonsPanel, bpy.types.Panel): col.prop(softbody, "speed") -class PHYSICS_PT_softbody_cache(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_softbody_cache(PhysicButtonsPanel, Panel): bl_label = "Soft Body Cache" bl_options = {'DEFAULT_CLOSED'} @@ -84,7 +85,7 @@ class PHYSICS_PT_softbody_cache(PhysicButtonsPanel, bpy.types.Panel): point_cache_ui(self, context, md.point_cache, softbody_panel_enabled(md), 'SOFTBODY') -class PHYSICS_PT_softbody_goal(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_softbody_goal(PhysicButtonsPanel, Panel): bl_label = "Soft Body Goal" bl_options = {'DEFAULT_CLOSED'} @@ -127,7 +128,7 @@ class PHYSICS_PT_softbody_goal(PhysicButtonsPanel, bpy.types.Panel): layout.prop_search(softbody, "vertex_group_goal", ob, "vertex_groups", text="Vertex Group") -class PHYSICS_PT_softbody_edge(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_softbody_edge(PhysicButtonsPanel, Panel): bl_label = "Soft Body Edges" bl_options = {'DEFAULT_CLOSED'} @@ -180,7 +181,7 @@ class PHYSICS_PT_softbody_edge(PhysicButtonsPanel, bpy.types.Panel): col.prop(softbody, "use_face_collision", text="Face") -class PHYSICS_PT_softbody_collision(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_softbody_collision(PhysicButtonsPanel, Panel): bl_label = "Soft Body Self Collision" bl_options = {'DEFAULT_CLOSED'} @@ -212,7 +213,7 @@ class PHYSICS_PT_softbody_collision(PhysicButtonsPanel, bpy.types.Panel): col.prop(softbody, "ball_damp", text="Dampening") -class PHYSICS_PT_softbody_solver(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_softbody_solver(PhysicButtonsPanel, Panel): bl_label = "Soft Body Solver" bl_options = {'DEFAULT_CLOSED'} @@ -248,7 +249,7 @@ class PHYSICS_PT_softbody_solver(PhysicButtonsPanel, bpy.types.Panel): layout.prop(softbody, "use_estimate_matrix") -class PHYSICS_PT_softbody_field_weights(PhysicButtonsPanel, bpy.types.Panel): +class PHYSICS_PT_softbody_field_weights(PhysicButtonsPanel, Panel): bl_label = "Soft Body Field Weights" bl_options = {'DEFAULT_CLOSED'} diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index 6d36db29a6c..fb14372ebea 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -18,27 +18,28 @@ # import bpy +from bpy.types import Menu, Panel -class RENDER_MT_presets(bpy.types.Menu): +class RENDER_MT_presets(Menu): bl_label = "Render Presets" preset_subdir = "render" preset_operator = "script.execute_preset" - draw = bpy.types.Menu.draw_preset + draw = Menu.draw_preset -class RENDER_MT_ffmpeg_presets(bpy.types.Menu): +class RENDER_MT_ffmpeg_presets(Menu): bl_label = "FFMPEG Presets" preset_subdir = "ffmpeg" preset_operator = "script.python_file_run" - draw = bpy.types.Menu.draw_preset + draw = Menu.draw_preset -class RENDER_MT_framerate_presets(bpy.types.Menu): +class RENDER_MT_framerate_presets(Menu): bl_label = "Frame Rate Presets" preset_subdir = "framerate" preset_operator = "script.execute_preset" - draw = bpy.types.Menu.draw_preset + draw = Menu.draw_preset class RenderButtonsPanel(): @@ -53,7 +54,7 @@ class RenderButtonsPanel(): return (context.scene and rd.use_game_engine is False) and (rd.engine in cls.COMPAT_ENGINES) -class RENDER_PT_render(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_render(RenderButtonsPanel, Panel): bl_label = "Render" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -69,7 +70,7 @@ class RENDER_PT_render(RenderButtonsPanel, bpy.types.Panel): layout.prop(rd, "display_mode", text="Display") -class RENDER_PT_layers(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_layers(RenderButtonsPanel, Panel): bl_label = "Layers" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -173,7 +174,7 @@ class RENDER_PT_layers(RenderButtonsPanel, bpy.types.Panel): row.prop(rl, "exclude_refraction", text="") -class RENDER_PT_dimensions(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_dimensions(RenderButtonsPanel, Panel): bl_label = "Dimensions" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -240,7 +241,7 @@ class RENDER_PT_dimensions(RenderButtonsPanel, bpy.types.Panel): subrow.prop(rd, "frame_map_new", text="New") -class RENDER_PT_antialiasing(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_antialiasing(RenderButtonsPanel, Panel): bl_label = "Anti-Aliasing" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -268,7 +269,7 @@ class RENDER_PT_antialiasing(RenderButtonsPanel, bpy.types.Panel): col.prop(rd, "filter_size", text="Size") -class RENDER_PT_motion_blur(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_motion_blur(RenderButtonsPanel, Panel): bl_label = "Sampled Motion Blur" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -294,7 +295,7 @@ class RENDER_PT_motion_blur(RenderButtonsPanel, bpy.types.Panel): row.prop(rd, "motion_blur_shutter") -class RENDER_PT_shading(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_shading(RenderButtonsPanel, Panel): bl_label = "Shading" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -318,7 +319,7 @@ class RENDER_PT_shading(RenderButtonsPanel, bpy.types.Panel): col.prop(rd, "alpha_mode", text="Alpha") -class RENDER_PT_performance(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_performance(RenderButtonsPanel, Panel): bl_label = "Performance" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -361,7 +362,7 @@ class RENDER_PT_performance(RenderButtonsPanel, bpy.types.Panel): sub.prop(rd, "use_local_coords", text="Local Coordinates") -class RENDER_PT_post_processing(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_post_processing(RenderButtonsPanel, Panel): bl_label = "Post Processing" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -398,7 +399,7 @@ class RENDER_PT_post_processing(RenderButtonsPanel, bpy.types.Panel): sub.prop(rd, "edge_color", text="") -class RENDER_PT_stamp(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_stamp(RenderButtonsPanel, Panel): bl_label = "Stamp" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -443,7 +444,7 @@ class RENDER_PT_stamp(RenderButtonsPanel, bpy.types.Panel): sub.prop(rd, "stamp_note_text", text="") -class RENDER_PT_output(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_output(RenderButtonsPanel, Panel): bl_label = "Output" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -543,7 +544,7 @@ class RENDER_PT_output(RenderButtonsPanel, bpy.types.Panel): col.prop(rd, "quicktime_audio_resampling_hq") -class RENDER_PT_encoding(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_encoding(RenderButtonsPanel, Panel): bl_label = "Encoding" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -600,7 +601,7 @@ class RENDER_PT_encoding(RenderButtonsPanel, bpy.types.Panel): split.prop(rd, "ffmpeg_audio_volume", slider=True) -class RENDER_PT_bake(RenderButtonsPanel, bpy.types.Panel): +class RENDER_PT_bake(RenderButtonsPanel, Panel): bl_label = "Bake" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py index 7725f661693..6e96e1228e7 100644 --- a/release/scripts/startup/bl_ui/properties_scene.py +++ b/release/scripts/startup/bl_ui/properties_scene.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Operator, Panel from rna_prop_ui import PropertyPanel @@ -31,7 +32,7 @@ class SceneButtonsPanel(): return context.scene -class SCENE_PT_scene(SceneButtonsPanel, bpy.types.Panel): +class SCENE_PT_scene(SceneButtonsPanel, Panel): bl_label = "Scene" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -43,7 +44,7 @@ class SCENE_PT_scene(SceneButtonsPanel, bpy.types.Panel): layout.prop(scene, "background_set", text="Background") -class SCENE_PT_unit(SceneButtonsPanel, bpy.types.Panel): +class SCENE_PT_unit(SceneButtonsPanel, Panel): bl_label = "Units" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -61,7 +62,7 @@ class SCENE_PT_unit(SceneButtonsPanel, bpy.types.Panel): row.prop(unit, "use_separate") -class SCENE_PT_keying_sets(SceneButtonsPanel, bpy.types.Panel): +class SCENE_PT_keying_sets(SceneButtonsPanel, Panel): bl_label = "Keying Sets" def draw(self, context): @@ -94,7 +95,7 @@ class SCENE_PT_keying_sets(SceneButtonsPanel, bpy.types.Panel): col.prop(ks, "bl_options") -class SCENE_PT_keying_set_paths(SceneButtonsPanel, bpy.types.Panel): +class SCENE_PT_keying_set_paths(SceneButtonsPanel, Panel): bl_label = "Active Keying Set" @classmethod @@ -144,7 +145,7 @@ class SCENE_PT_keying_set_paths(SceneButtonsPanel, bpy.types.Panel): col.prop(ksp, "bl_options") -class SCENE_PT_physics(SceneButtonsPanel, bpy.types.Panel): +class SCENE_PT_physics(SceneButtonsPanel, Panel): bl_label = "Gravity" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -161,7 +162,7 @@ class SCENE_PT_physics(SceneButtonsPanel, bpy.types.Panel): layout.prop(scene, "gravity", text="") -class SCENE_PT_simplify(SceneButtonsPanel, bpy.types.Panel): +class SCENE_PT_simplify(SceneButtonsPanel, Panel): bl_label = "Simplify" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -190,7 +191,7 @@ class SCENE_PT_simplify(SceneButtonsPanel, bpy.types.Panel): col.prop(rd, "simplify_ao_sss", text="AO and SSS") -class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, bpy.types.Panel): +class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} _context_path = "scene" _property_type = bpy.types.Scene @@ -198,7 +199,7 @@ class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, bpy.types.Panel): # XXX, move operator to op/ dir -class ANIM_OT_keying_set_export(bpy.types.Operator): +class ANIM_OT_keying_set_export(Operator): "Export Keying Set to a python script." bl_idname = "anim.keying_set_export" bl_label = "Export Keying Set..." diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py index 7ca8818cbd2..ead65b92c3f 100644 --- a/release/scripts/startup/bl_ui/properties_texture.py +++ b/release/scripts/startup/bl_ui/properties_texture.py @@ -18,10 +18,11 @@ # import bpy +from bpy.types import Menu, Panel from rna_prop_ui import PropertyPanel -class TEXTURE_MT_specials(bpy.types.Menu): +class TEXTURE_MT_specials(Menu): bl_label = "Texture Specials" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -32,7 +33,7 @@ class TEXTURE_MT_specials(bpy.types.Menu): layout.operator("texture.slot_paste", icon='PASTEDOWN') -class TEXTURE_MT_envmap_specials(bpy.types.Menu): +class TEXTURE_MT_envmap_specials(Menu): bl_label = "Environment Map Specials" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -80,7 +81,7 @@ class TextureButtonsPanel(): return tex and (tex.type != 'NONE' or tex.use_nodes) and (context.scene.render.engine in cls.COMPAT_ENGINES) -class TEXTURE_PT_context_texture(TextureButtonsPanel, bpy.types.Panel): +class TEXTURE_PT_context_texture(TextureButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -150,7 +151,7 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel, bpy.types.Panel): split.prop(tex, "type", text="") -class TEXTURE_PT_preview(TextureButtonsPanel, bpy.types.Panel): +class TEXTURE_PT_preview(TextureButtonsPanel, Panel): bl_label = "Preview" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -167,7 +168,7 @@ class TEXTURE_PT_preview(TextureButtonsPanel, bpy.types.Panel): layout.template_preview(tex, slot=slot) -class TEXTURE_PT_colors(TextureButtonsPanel, bpy.types.Panel): +class TEXTURE_PT_colors(TextureButtonsPanel, Panel): bl_label = "Colors" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -223,7 +224,7 @@ class TextureTypePanel(TextureButtonsPanel): return tex and ((tex.type == cls.tex_type and not tex.use_nodes) and (engine in cls.COMPAT_ENGINES)) -class TEXTURE_PT_clouds(TextureTypePanel, bpy.types.Panel): +class TEXTURE_PT_clouds(TextureTypePanel, Panel): bl_label = "Clouds" tex_type = 'CLOUDS' COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -247,7 +248,7 @@ class TEXTURE_PT_clouds(TextureTypePanel, bpy.types.Panel): split.prop(tex, "nabla", text="Nabla") -class TEXTURE_PT_wood(TextureTypePanel, bpy.types.Panel): +class TEXTURE_PT_wood(TextureTypePanel, Panel): bl_label = "Wood" tex_type = 'WOOD' COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -276,7 +277,7 @@ class TEXTURE_PT_wood(TextureTypePanel, bpy.types.Panel): split.prop(tex, "nabla") -class TEXTURE_PT_marble(TextureTypePanel, bpy.types.Panel): +class TEXTURE_PT_marble(TextureTypePanel, Panel): bl_label = "Marble" tex_type = 'MARBLE' COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -303,7 +304,7 @@ class TEXTURE_PT_marble(TextureTypePanel, bpy.types.Panel): col.prop(tex, "nabla") -class TEXTURE_PT_magic(TextureTypePanel, bpy.types.Panel): +class TEXTURE_PT_magic(TextureTypePanel, Panel): bl_label = "Magic" tex_type = 'MAGIC' COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -318,7 +319,7 @@ class TEXTURE_PT_magic(TextureTypePanel, bpy.types.Panel): row.prop(tex, "turbulence") -class TEXTURE_PT_blend(TextureTypePanel, bpy.types.Panel): +class TEXTURE_PT_blend(TextureTypePanel, Panel): bl_label = "Blend" tex_type = 'BLEND' COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -336,7 +337,7 @@ class TEXTURE_PT_blend(TextureTypePanel, bpy.types.Panel): sub.prop(tex, "use_flip_axis", expand=True) -class TEXTURE_PT_stucci(TextureTypePanel, bpy.types.Panel): +class TEXTURE_PT_stucci(TextureTypePanel, Panel): bl_label = "Stucci" tex_type = 'STUCCI' COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -356,7 +357,7 @@ class TEXTURE_PT_stucci(TextureTypePanel, bpy.types.Panel): row.prop(tex, "turbulence") -class TEXTURE_PT_image(TextureTypePanel, bpy.types.Panel): +class TEXTURE_PT_image(TextureTypePanel, Panel): bl_label = "Image" tex_type = 'IMAGE' COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -382,7 +383,7 @@ def texture_filter_common(tex, layout): layout.prop(tex, "use_filter_size_min") -class TEXTURE_PT_image_sampling(TextureTypePanel, bpy.types.Panel): +class TEXTURE_PT_image_sampling(TextureTypePanel, Panel): bl_label = "Image Sampling" bl_options = {'DEFAULT_CLOSED'} tex_type = 'IMAGE' @@ -423,7 +424,7 @@ class TEXTURE_PT_image_sampling(TextureTypePanel, bpy.types.Panel): texture_filter_common(tex, col) -class TEXTURE_PT_image_mapping(TextureTypePanel, bpy.types.Panel): +class TEXTURE_PT_image_mapping(TextureTypePanel, Panel): bl_label = "Image Mapping" bl_options = {'DEFAULT_CLOSED'} tex_type = 'IMAGE' @@ -479,7 +480,7 @@ class TEXTURE_PT_image_mapping(TextureTypePanel, bpy.types.Panel): col.prop(tex, "crop_max_y", text="Y") -class TEXTURE_PT_envmap(TextureTypePanel, bpy.types.Panel): +class TEXTURE_PT_envmap(TextureTypePanel, Panel): bl_label = "Environment Map" tex_type = 'ENVIRONMENT_MAP' COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -517,7 +518,7 @@ class TEXTURE_PT_envmap(TextureTypePanel, bpy.types.Panel): col.prop(env, "clip_end", text="End") -class TEXTURE_PT_envmap_sampling(TextureTypePanel, bpy.types.Panel): +class TEXTURE_PT_envmap_sampling(TextureTypePanel, Panel): bl_label = "Environment Map Sampling" bl_options = {'DEFAULT_CLOSED'} tex_type = 'ENVIRONMENT_MAP' @@ -531,7 +532,7 @@ class TEXTURE_PT_envmap_sampling(TextureTypePanel, bpy.types.Panel): texture_filter_common(tex, layout) -class TEXTURE_PT_musgrave(TextureTypePanel, bpy.types.Panel): +class TEXTURE_PT_musgrave(TextureTypePanel, Panel): bl_label = "Musgrave" tex_type = 'MUSGRAVE' COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -568,7 +569,7 @@ class TEXTURE_PT_musgrave(TextureTypePanel, bpy.types.Panel): row.prop(tex, "nabla") -class TEXTURE_PT_voronoi(TextureTypePanel, bpy.types.Panel): +class TEXTURE_PT_voronoi(TextureTypePanel, Panel): bl_label = "Voronoi" tex_type = 'VORONOI' COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -604,7 +605,7 @@ class TEXTURE_PT_voronoi(TextureTypePanel, bpy.types.Panel): row.prop(tex, "nabla") -class TEXTURE_PT_distortednoise(TextureTypePanel, bpy.types.Panel): +class TEXTURE_PT_distortednoise(TextureTypePanel, Panel): bl_label = "Distorted Noise" tex_type = 'DISTORTED_NOISE' COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -626,7 +627,7 @@ class TEXTURE_PT_distortednoise(TextureTypePanel, bpy.types.Panel): split.prop(tex, "nabla") -class TEXTURE_PT_voxeldata(TextureButtonsPanel, bpy.types.Panel): +class TEXTURE_PT_voxeldata(TextureButtonsPanel, Panel): bl_label = "Voxel Data" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -666,7 +667,7 @@ class TEXTURE_PT_voxeldata(TextureButtonsPanel, bpy.types.Panel): layout.prop(vd, "intensity") -class TEXTURE_PT_pointdensity(TextureButtonsPanel, bpy.types.Panel): +class TEXTURE_PT_pointdensity(TextureButtonsPanel, Panel): bl_label = "Point Density" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -732,7 +733,7 @@ class TEXTURE_PT_pointdensity(TextureButtonsPanel, bpy.types.Panel): col.template_curve_mapping(pd, "falloff_curve", brush=False) -class TEXTURE_PT_pointdensity_turbulence(TextureButtonsPanel, bpy.types.Panel): +class TEXTURE_PT_pointdensity_turbulence(TextureButtonsPanel, Panel): bl_label = "Turbulence" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -769,7 +770,7 @@ class TEXTURE_PT_pointdensity_turbulence(TextureButtonsPanel, bpy.types.Panel): col.prop(pd, "turbulence_strength") -class TEXTURE_PT_mapping(TextureSlotPanel, bpy.types.Panel): +class TEXTURE_PT_mapping(TextureSlotPanel, Panel): bl_label = "Mapping" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -857,7 +858,7 @@ class TEXTURE_PT_mapping(TextureSlotPanel, bpy.types.Panel): row.column().prop(tex, "scale") -class TEXTURE_PT_influence(TextureSlotPanel, bpy.types.Panel): +class TEXTURE_PT_influence(TextureSlotPanel, Panel): bl_label = "Influence" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -1033,7 +1034,7 @@ class TEXTURE_PT_influence(TextureSlotPanel, bpy.types.Panel): sub.prop(tex, "bump_objectspace", text="Space") -class TEXTURE_PT_custom_props(TextureButtonsPanel, PropertyPanel, bpy.types.Panel): +class TEXTURE_PT_custom_props(TextureButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} _context_path = "texture" _property_type = bpy.types.Texture diff --git a/release/scripts/startup/bl_ui/properties_world.py b/release/scripts/startup/bl_ui/properties_world.py index c577af01374..71ee03296a0 100644 --- a/release/scripts/startup/bl_ui/properties_world.py +++ b/release/scripts/startup/bl_ui/properties_world.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Panel from rna_prop_ui import PropertyPanel @@ -32,7 +33,7 @@ class WorldButtonsPanel(): return (context.world and context.scene.render.engine in cls.COMPAT_ENGINES) -class WORLD_PT_context_world(WorldButtonsPanel, bpy.types.Panel): +class WORLD_PT_context_world(WorldButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -61,7 +62,7 @@ class WORLD_PT_context_world(WorldButtonsPanel, bpy.types.Panel): split.label(text=str(texture_count), icon='TEXTURE') -class WORLD_PT_preview(WorldButtonsPanel, bpy.types.Panel): +class WORLD_PT_preview(WorldButtonsPanel, Panel): bl_label = "Preview" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -74,7 +75,7 @@ class WORLD_PT_preview(WorldButtonsPanel, bpy.types.Panel): self.layout.template_preview(context.world) -class WORLD_PT_world(WorldButtonsPanel, bpy.types.Panel): +class WORLD_PT_world(WorldButtonsPanel, Panel): bl_label = "World" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -99,7 +100,7 @@ class WORLD_PT_world(WorldButtonsPanel, bpy.types.Panel): row.prop(world, "color_range") -class WORLD_PT_ambient_occlusion(WorldButtonsPanel, bpy.types.Panel): +class WORLD_PT_ambient_occlusion(WorldButtonsPanel, Panel): bl_label = "Ambient Occlusion" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -118,7 +119,7 @@ class WORLD_PT_ambient_occlusion(WorldButtonsPanel, bpy.types.Panel): split.prop(light, "ao_blend_type", text="") -class WORLD_PT_environment_lighting(WorldButtonsPanel, bpy.types.Panel): +class WORLD_PT_environment_lighting(WorldButtonsPanel, Panel): bl_label = "Environment Lighting" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -137,7 +138,7 @@ class WORLD_PT_environment_lighting(WorldButtonsPanel, bpy.types.Panel): split.prop(light, "environment_color", text="") -class WORLD_PT_indirect_lighting(WorldButtonsPanel, bpy.types.Panel): +class WORLD_PT_indirect_lighting(WorldButtonsPanel, Panel): bl_label = "Indirect Lighting" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -159,7 +160,7 @@ class WORLD_PT_indirect_lighting(WorldButtonsPanel, bpy.types.Panel): layout.label(text="Only works with Approximate gather method") -class WORLD_PT_gather(WorldButtonsPanel, bpy.types.Panel): +class WORLD_PT_gather(WorldButtonsPanel, Panel): bl_label = "Gather" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -207,7 +208,7 @@ class WORLD_PT_gather(WorldButtonsPanel, bpy.types.Panel): col.prop(light, "correction") -class WORLD_PT_mist(WorldButtonsPanel, bpy.types.Panel): +class WORLD_PT_mist(WorldButtonsPanel, Panel): bl_label = "Mist" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -236,7 +237,7 @@ class WORLD_PT_mist(WorldButtonsPanel, bpy.types.Panel): layout.prop(world.mist_settings, "falloff") -class WORLD_PT_stars(WorldButtonsPanel, bpy.types.Panel): +class WORLD_PT_stars(WorldButtonsPanel, Panel): bl_label = "Stars" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -263,7 +264,7 @@ class WORLD_PT_stars(WorldButtonsPanel, bpy.types.Panel): col.prop(world.star_settings, "average_separation", text="Separation") -class WORLD_PT_custom_props(WorldButtonsPanel, PropertyPanel, bpy.types.Panel): +class WORLD_PT_custom_props(WorldButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} _context_path = "world" _property_type = bpy.types.World diff --git a/release/scripts/startup/bl_ui/space_console.py b/release/scripts/startup/bl_ui/space_console.py index da6c102100b..5064f0744af 100644 --- a/release/scripts/startup/bl_ui/space_console.py +++ b/release/scripts/startup/bl_ui/space_console.py @@ -18,10 +18,11 @@ # import bpy +from bpy.types import Header, Menu, Operator from bpy.props import StringProperty -class CONSOLE_HT_header(bpy.types.Header): +class CONSOLE_HT_header(Header): bl_space_type = 'CONSOLE' def draw(self, context): @@ -38,7 +39,7 @@ class CONSOLE_HT_header(bpy.types.Header): row.operator("console.autocomplete", text="Autocomplete") -class CONSOLE_MT_console(bpy.types.Menu): +class CONSOLE_MT_console(Menu): bl_label = "Console" def draw(self, context): @@ -55,7 +56,7 @@ class CONSOLE_MT_console(bpy.types.Menu): layout.operator("screen.screen_full_area") -class CONSOLE_MT_language(bpy.types.Menu): +class CONSOLE_MT_language(Menu): bl_label = "Languages..." def draw(self, context): @@ -82,7 +83,7 @@ def add_scrollback(text, text_type): type=text_type) -class ConsoleExec(bpy.types.Operator): +class ConsoleExec(Operator): '''Execute the current console line as a python expression''' bl_idname = "console.execute" bl_label = "Console Execute" @@ -100,7 +101,7 @@ class ConsoleExec(bpy.types.Operator): return {'FINISHED'} -class ConsoleAutocomplete(bpy.types.Operator): +class ConsoleAutocomplete(Operator): '''Evaluate the namespace up until the cursor and give a list of options or complete the name if there is only one''' bl_idname = "console.autocomplete" bl_label = "Console Autocomplete" @@ -117,7 +118,7 @@ class ConsoleAutocomplete(bpy.types.Operator): return {'FINISHED'} -class ConsoleBanner(bpy.types.Operator): +class ConsoleBanner(Operator): '''Print a message whem the terminal initializes''' bl_idname = "console.banner" bl_label = "Console Banner" @@ -139,7 +140,7 @@ class ConsoleBanner(bpy.types.Operator): return {'FINISHED'} -class ConsoleLanguage(bpy.types.Operator): +class ConsoleLanguage(Operator): '''Set the current language for this console''' bl_idname = "console.language" bl_label = "Console Language" diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 930a2029d32..73624b490bf 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -19,6 +19,7 @@ # import bpy +from bpy.types import Header, Menu ####################################### @@ -84,7 +85,7 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False): ####################################### # DopeSheet Editor - General/Standard UI -class DOPESHEET_HT_header(bpy.types.Header): +class DOPESHEET_HT_header(Header): bl_space_type = 'DOPESHEET_EDITOR' def draw(self, context): @@ -134,7 +135,7 @@ class DOPESHEET_HT_header(bpy.types.Header): row.operator("action.paste", text="", icon='PASTEDOWN') -class DOPESHEET_MT_view(bpy.types.Menu): +class DOPESHEET_MT_view(Menu): bl_label = "View" def draw(self, context): @@ -170,7 +171,7 @@ class DOPESHEET_MT_view(bpy.types.Menu): layout.operator("screen.screen_full_area") -class DOPESHEET_MT_select(bpy.types.Menu): +class DOPESHEET_MT_select(Menu): bl_label = "Select" def draw(self, context): @@ -206,7 +207,7 @@ class DOPESHEET_MT_select(bpy.types.Menu): layout.operator("action.select_linked") -class DOPESHEET_MT_marker(bpy.types.Menu): +class DOPESHEET_MT_marker(Menu): bl_label = "Marker" def draw(self, context): @@ -237,7 +238,7 @@ class DOPESHEET_MT_marker(bpy.types.Menu): ####################################### # Keyframe Editing -class DOPESHEET_MT_channel(bpy.types.Menu): +class DOPESHEET_MT_channel(Menu): bl_label = "Channel" def draw(self, context): @@ -268,7 +269,7 @@ class DOPESHEET_MT_channel(bpy.types.Menu): layout.operator("anim.channels_fcurves_enable") -class DOPESHEET_MT_key(bpy.types.Menu): +class DOPESHEET_MT_key(Menu): bl_label = "Key" def draw(self, context): @@ -301,7 +302,7 @@ class DOPESHEET_MT_key(bpy.types.Menu): layout.operator("action.paste") -class DOPESHEET_MT_key_transform(bpy.types.Menu): +class DOPESHEET_MT_key_transform(Menu): bl_label = "Transform" def draw(self, context): @@ -317,7 +318,7 @@ class DOPESHEET_MT_key_transform(bpy.types.Menu): ####################################### # Grease Pencil Editing -class DOPESHEET_MT_gpencil_channel(bpy.types.Menu): +class DOPESHEET_MT_gpencil_channel(Menu): bl_label = "Channel" def draw(self, context): @@ -345,7 +346,7 @@ class DOPESHEET_MT_gpencil_channel(bpy.types.Menu): #layout.operator_menu_enum("anim.channels_move", "direction", text="Move...") -class DOPESHEET_MT_gpencil_frame(bpy.types.Menu): +class DOPESHEET_MT_gpencil_frame(Menu): bl_label = "Frame" def draw(self, context): diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py index 73fe1a97252..cf0d10c5844 100644 --- a/release/scripts/startup/bl_ui/space_filebrowser.py +++ b/release/scripts/startup/bl_ui/space_filebrowser.py @@ -18,9 +18,10 @@ # import bpy +from bpy.types import Header -class FILEBROWSER_HT_header(bpy.types.Header): +class FILEBROWSER_HT_header(Header): bl_space_type = 'FILE_BROWSER' def draw(self, context): diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index bfc1a0e3a23..f6ba6ed7942 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -19,9 +19,10 @@ # import bpy +from bpy.types import Header, Menu -class GRAPH_HT_header(bpy.types.Header): +class GRAPH_HT_header(Header): bl_space_type = 'GRAPH_EDITOR' def draw(self, context): @@ -61,7 +62,7 @@ class GRAPH_HT_header(bpy.types.Header): row.operator("graph.ghost_curves_create", text="", icon='GHOST_ENABLED') -class GRAPH_MT_view(bpy.types.Menu): +class GRAPH_MT_view(Menu): bl_label = "View" def draw(self, context): @@ -107,7 +108,7 @@ class GRAPH_MT_view(bpy.types.Menu): layout.operator("screen.screen_full_area") -class GRAPH_MT_select(bpy.types.Menu): +class GRAPH_MT_select(Menu): bl_label = "Select" def draw(self, context): @@ -142,7 +143,7 @@ class GRAPH_MT_select(bpy.types.Menu): layout.operator("graph.select_linked") -class GRAPH_MT_marker(bpy.types.Menu): +class GRAPH_MT_marker(Menu): bl_label = "Marker" def draw(self, context): @@ -163,7 +164,7 @@ class GRAPH_MT_marker(bpy.types.Menu): # TODO: pose markers for action edit mode only? -class GRAPH_MT_channel(bpy.types.Menu): +class GRAPH_MT_channel(Menu): bl_label = "Channel" def draw(self, context): @@ -195,7 +196,7 @@ class GRAPH_MT_channel(bpy.types.Menu): layout.operator("anim.channels_fcurves_enable") -class GRAPH_MT_key(bpy.types.Menu): +class GRAPH_MT_key(Menu): bl_label = "Key" def draw(self, context): @@ -234,7 +235,7 @@ class GRAPH_MT_key(bpy.types.Menu): layout.operator("graph.euler_filter", text="Discontinuity (Euler) Filter") -class GRAPH_MT_key_transform(bpy.types.Menu): +class GRAPH_MT_key_transform(Menu): bl_label = "Transform" def draw(self, context): diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index fa5579ea2e0..0278863ca27 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Header, Menu, Panel class BrushButtonsPanel(): @@ -31,7 +32,7 @@ class BrushButtonsPanel(): return sima.show_paint and toolsettings.brush -class IMAGE_MT_view(bpy.types.Menu): +class IMAGE_MT_view(Menu): bl_label = "View" def draw(self, context): @@ -79,7 +80,7 @@ class IMAGE_MT_view(bpy.types.Menu): layout.operator("screen.screen_full_area") -class IMAGE_MT_select(bpy.types.Menu): +class IMAGE_MT_select(Menu): bl_label = "Select" def draw(self, context): @@ -100,7 +101,7 @@ class IMAGE_MT_select(bpy.types.Menu): layout.operator("uv.select_linked") -class IMAGE_MT_image(bpy.types.Menu): +class IMAGE_MT_image(Menu): bl_label = "Image" def draw(self, context): @@ -151,7 +152,7 @@ class IMAGE_MT_image(bpy.types.Menu): layout.prop(sima, "use_image_paint") -class IMAGE_MT_image_invert(bpy.types.Menu): +class IMAGE_MT_image_invert(Menu): bl_label = "Invert" def draw(self, context): @@ -177,7 +178,7 @@ class IMAGE_MT_image_invert(bpy.types.Menu): op.invert_a = True -class IMAGE_MT_uvs_showhide(bpy.types.Menu): +class IMAGE_MT_uvs_showhide(Menu): bl_label = "Show/Hide Faces" def draw(self, context): @@ -188,7 +189,7 @@ class IMAGE_MT_uvs_showhide(bpy.types.Menu): layout.operator("uv.hide", text="Hide Unselected").unselected = True -class IMAGE_MT_uvs_transform(bpy.types.Menu): +class IMAGE_MT_uvs_transform(Menu): bl_label = "Transform" def draw(self, context): @@ -203,7 +204,7 @@ class IMAGE_MT_uvs_transform(bpy.types.Menu): layout.operator("transform.shear") -class IMAGE_MT_uvs_snap(bpy.types.Menu): +class IMAGE_MT_uvs_snap(Menu): bl_label = "Snap" def draw(self, context): @@ -220,7 +221,7 @@ class IMAGE_MT_uvs_snap(bpy.types.Menu): layout.operator("uv.snap_cursor", text="Cursor to Selected").target = 'SELECTED' -class IMAGE_MT_uvs_mirror(bpy.types.Menu): +class IMAGE_MT_uvs_mirror(Menu): bl_label = "Mirror" def draw(self, context): @@ -231,7 +232,7 @@ class IMAGE_MT_uvs_mirror(bpy.types.Menu): layout.operator("transform.mirror", text="Y Axis").constraint_axis[1] = True -class IMAGE_MT_uvs_weldalign(bpy.types.Menu): +class IMAGE_MT_uvs_weldalign(Menu): bl_label = "Weld/Align" def draw(self, context): @@ -241,7 +242,7 @@ class IMAGE_MT_uvs_weldalign(bpy.types.Menu): layout.operator_enum("uv.align", "axis") # W, 2/3/4 -class IMAGE_MT_uvs(bpy.types.Menu): +class IMAGE_MT_uvs(Menu): bl_label = "UVs" def draw(self, context): @@ -286,7 +287,7 @@ class IMAGE_MT_uvs(bpy.types.Menu): layout.menu("IMAGE_MT_uvs_showhide") -class IMAGE_MT_uvs_select_mode(bpy.types.Menu): +class IMAGE_MT_uvs_select_mode(Menu): bl_label = "UV Select Mode" def draw(self, context): @@ -328,7 +329,7 @@ class IMAGE_MT_uvs_select_mode(bpy.types.Menu): prop.data_path = "tool_settings.uv_select_mode" -class IMAGE_HT_header(bpy.types.Header): +class IMAGE_HT_header(Header): bl_space_type = 'IMAGE_EDITOR' def draw(self, context): @@ -412,7 +413,7 @@ class IMAGE_HT_header(bpy.types.Header): layout.prop(sima, "use_realtime_update", text="", icon_only=True, icon='LOCKED') -class IMAGE_PT_image_properties(bpy.types.Panel): +class IMAGE_PT_image_properties(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' bl_label = "Image" @@ -431,7 +432,7 @@ class IMAGE_PT_image_properties(bpy.types.Panel): layout.template_image(sima, "image", iuser) -class IMAGE_PT_game_properties(bpy.types.Panel): +class IMAGE_PT_game_properties(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' bl_label = "Game Properties" @@ -475,7 +476,7 @@ class IMAGE_PT_game_properties(bpy.types.Panel): col.prop(ima, "mapping", expand=True) -class IMAGE_PT_view_histogram(bpy.types.Panel): +class IMAGE_PT_view_histogram(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'PREVIEW' bl_label = "Histogram" @@ -494,7 +495,7 @@ class IMAGE_PT_view_histogram(bpy.types.Panel): layout.prop(sima.scopes.histogram, "mode", icon_only=True) -class IMAGE_PT_view_waveform(bpy.types.Panel): +class IMAGE_PT_view_waveform(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'PREVIEW' bl_label = "Waveform" @@ -514,7 +515,7 @@ class IMAGE_PT_view_waveform(bpy.types.Panel): sub.prop(sima.scopes, "waveform_mode", text="", icon_only=True) -class IMAGE_PT_view_vectorscope(bpy.types.Panel): +class IMAGE_PT_view_vectorscope(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'PREVIEW' bl_label = "Vectorscope" @@ -532,7 +533,7 @@ class IMAGE_PT_view_vectorscope(bpy.types.Panel): layout.prop(sima.scopes, "vectorscope_alpha") -class IMAGE_PT_sample_line(bpy.types.Panel): +class IMAGE_PT_sample_line(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'PREVIEW' bl_label = "Sample Line" @@ -550,7 +551,7 @@ class IMAGE_PT_sample_line(bpy.types.Panel): layout.prop(sima.sample_histogram, "mode") -class IMAGE_PT_scope_sample(bpy.types.Panel): +class IMAGE_PT_scope_sample(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'PREVIEW' bl_label = "Scope Samples" @@ -571,7 +572,7 @@ class IMAGE_PT_scope_sample(bpy.types.Panel): row.prop(sima.scopes, "accuracy") -class IMAGE_PT_view_properties(bpy.types.Panel): +class IMAGE_PT_view_properties(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' bl_label = "Display" @@ -630,7 +631,7 @@ class IMAGE_PT_view_properties(bpy.types.Panel): sub.row().prop(uvedit, "draw_stretch_type", expand=True) -class IMAGE_PT_paint(bpy.types.Panel): +class IMAGE_PT_paint(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' bl_label = "Paint" @@ -675,7 +676,7 @@ class IMAGE_PT_paint(bpy.types.Panel): col.prop(brush, "clone_alpha", text="Alpha") -class IMAGE_PT_tools_brush_texture(BrushButtonsPanel, bpy.types.Panel): +class IMAGE_PT_tools_brush_texture(BrushButtonsPanel, Panel): bl_label = "Texture" bl_options = {'DEFAULT_CLOSED'} @@ -690,7 +691,7 @@ class IMAGE_PT_tools_brush_texture(BrushButtonsPanel, bpy.types.Panel): col.prop(brush, "use_fixed_texture") -class IMAGE_PT_tools_brush_tool(BrushButtonsPanel, bpy.types.Panel): +class IMAGE_PT_tools_brush_tool(BrushButtonsPanel, Panel): bl_label = "Tool" bl_options = {'DEFAULT_CLOSED'} @@ -710,7 +711,7 @@ class IMAGE_PT_tools_brush_tool(BrushButtonsPanel, bpy.types.Panel): row.prop(brush, "use_paint_image", text="", icon='TPAINT_HLT') -class IMAGE_PT_paint_stroke(BrushButtonsPanel, bpy.types.Panel): +class IMAGE_PT_paint_stroke(BrushButtonsPanel, Panel): bl_label = "Paint Stroke" bl_options = {'DEFAULT_CLOSED'} @@ -734,7 +735,7 @@ class IMAGE_PT_paint_stroke(BrushButtonsPanel, bpy.types.Panel): layout.prop(brush, "use_wrap") -class IMAGE_PT_paint_curve(BrushButtonsPanel, bpy.types.Panel): +class IMAGE_PT_paint_curve(BrushButtonsPanel, Panel): bl_label = "Paint Curve" bl_options = {'DEFAULT_CLOSED'} diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index ee214bd4178..12873743a23 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -18,9 +18,10 @@ # import bpy +from bpy.types import Header, Menu, Operator -class INFO_HT_header(bpy.types.Header): +class INFO_HT_header(Header): bl_space_type = 'INFO' def draw(self, context): @@ -86,7 +87,7 @@ class INFO_HT_header(bpy.types.Header): """ -class INFO_MT_report(bpy.types.Menu): +class INFO_MT_report(Menu): bl_label = "Report" def draw(self, context): @@ -98,7 +99,7 @@ class INFO_MT_report(bpy.types.Menu): layout.operator("console.report_copy") -class INFO_MT_file(bpy.types.Menu): +class INFO_MT_file(Menu): bl_label = "File" def draw(self, context): @@ -152,7 +153,7 @@ class INFO_MT_file(bpy.types.Menu): layout.operator("wm.quit_blender", text="Quit", icon='QUIT') -class INFO_MT_file_import(bpy.types.Menu): +class INFO_MT_file_import(Menu): bl_idname = "INFO_MT_file_import" bl_label = "Import" @@ -161,7 +162,7 @@ class INFO_MT_file_import(bpy.types.Menu): self.layout.operator("wm.collada_import", text="COLLADA (.dae)") -class INFO_MT_file_export(bpy.types.Menu): +class INFO_MT_file_export(Menu): bl_idname = "INFO_MT_file_export" bl_label = "Export" @@ -170,7 +171,7 @@ class INFO_MT_file_export(bpy.types.Menu): self.layout.operator("wm.collada_export", text="COLLADA (.dae)") -class INFO_MT_file_external_data(bpy.types.Menu): +class INFO_MT_file_external_data(Menu): bl_label = "External Data" def draw(self, context): @@ -187,7 +188,7 @@ class INFO_MT_file_external_data(bpy.types.Menu): layout.operator("file.find_missing_files") -class INFO_MT_mesh_add(bpy.types.Menu): +class INFO_MT_mesh_add(Menu): bl_idname = "INFO_MT_mesh_add" bl_label = "Mesh" @@ -207,7 +208,7 @@ class INFO_MT_mesh_add(bpy.types.Menu): layout.operator("mesh.primitive_torus_add", text="Torus", icon='MESH_TORUS') -class INFO_MT_curve_add(bpy.types.Menu): +class INFO_MT_curve_add(Menu): bl_idname = "INFO_MT_curve_add" bl_label = "Curve" @@ -221,7 +222,7 @@ class INFO_MT_curve_add(bpy.types.Menu): layout.operator("curve.primitive_nurbs_path_add", icon='CURVE_PATH', text="Path") -class INFO_MT_edit_curve_add(bpy.types.Menu): +class INFO_MT_edit_curve_add(Menu): bl_idname = "INFO_MT_edit_curve_add" bl_label = "Add" @@ -237,7 +238,7 @@ class INFO_MT_edit_curve_add(bpy.types.Menu): INFO_MT_curve_add.draw(self, context) -class INFO_MT_surface_add(bpy.types.Menu): +class INFO_MT_surface_add(Menu): bl_idname = "INFO_MT_surface_add" bl_label = "Surface" @@ -252,7 +253,7 @@ class INFO_MT_surface_add(bpy.types.Menu): layout.operator("surface.primitive_nurbs_surface_torus_add", icon='SURFACE_NTORUS', text="NURBS Torus") -class INFO_MT_armature_add(bpy.types.Menu): +class INFO_MT_armature_add(Menu): bl_idname = "INFO_MT_armature_add" bl_label = "Armature" @@ -262,7 +263,7 @@ class INFO_MT_armature_add(bpy.types.Menu): layout.operator("object.armature_add", text="Single Bone", icon='BONE_DATA') -class INFO_MT_add(bpy.types.Menu): +class INFO_MT_add(Menu): bl_label = "Add" def draw(self, context): @@ -302,7 +303,7 @@ class INFO_MT_add(bpy.types.Menu): layout.operator_menu_enum("object.group_instance_add", "group", text="Group Instance", icon='OUTLINER_OB_EMPTY') -class INFO_MT_game(bpy.types.Menu): +class INFO_MT_game(Menu): bl_label = "Game" def draw(self, context): @@ -323,7 +324,7 @@ class INFO_MT_game(bpy.types.Menu): layout.prop(gs, "use_auto_start") -class INFO_MT_render(bpy.types.Menu): +class INFO_MT_render(Menu): bl_label = "Render" def draw(self, context): @@ -343,7 +344,7 @@ class INFO_MT_render(bpy.types.Menu): layout.operator("render.play_rendered_anim") -class INFO_MT_help(bpy.types.Menu): +class INFO_MT_help(Menu): bl_label = "Help" def draw(self, context): @@ -379,7 +380,7 @@ class INFO_MT_help(bpy.types.Menu): # Help operators -class HELP_OT_operator_cheat_sheet(bpy.types.Operator): +class HELP_OT_operator_cheat_sheet(Operator): bl_idname = "help.operator_cheat_sheet" bl_label = "Operator Cheat Sheet" diff --git a/release/scripts/startup/bl_ui/space_logic.py b/release/scripts/startup/bl_ui/space_logic.py index 7f7aba71a46..1b774539d0f 100644 --- a/release/scripts/startup/bl_ui/space_logic.py +++ b/release/scripts/startup/bl_ui/space_logic.py @@ -18,9 +18,10 @@ # import bpy +from bpy.types import Header, Menu, Panel -class LOGIC_PT_properties(bpy.types.Panel): +class LOGIC_PT_properties(Panel): bl_space_type = 'LOGIC_EDITOR' bl_region_type = 'UI' bl_label = "Properties" @@ -49,7 +50,7 @@ class LOGIC_PT_properties(bpy.types.Panel): row.operator("object.game_property_remove", text="", icon='X', emboss=False).index = i -class LOGIC_MT_logicbricks_add(bpy.types.Menu): +class LOGIC_MT_logicbricks_add(Menu): bl_label = "Add" def draw(self, context): @@ -60,7 +61,7 @@ class LOGIC_MT_logicbricks_add(bpy.types.Menu): layout.operator_menu_enum("logic.actuator_add", "type", text="Actuator") -class LOGIC_HT_header(bpy.types.Header): +class LOGIC_HT_header(Header): bl_space_type = 'LOGIC_EDITOR' def draw(self, context): @@ -76,7 +77,7 @@ class LOGIC_HT_header(bpy.types.Header): #sub.menu("LOGIC_MT_add") -class LOGIC_MT_view(bpy.types.Menu): +class LOGIC_MT_view(Menu): bl_label = "View" def draw(self, context): diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py index 717adb3baa8..55f2dabba74 100644 --- a/release/scripts/startup/bl_ui/space_nla.py +++ b/release/scripts/startup/bl_ui/space_nla.py @@ -19,9 +19,10 @@ # import bpy +from bpy.types import Header, Menu -class NLA_HT_header(bpy.types.Header): +class NLA_HT_header(Header): bl_space_type = 'NLA_EDITOR' def draw(self, context): @@ -48,7 +49,7 @@ class NLA_HT_header(bpy.types.Header): layout.prop(st, "auto_snap", text="") -class NLA_MT_view(bpy.types.Menu): +class NLA_MT_view(Menu): bl_label = "View" def draw(self, context): @@ -78,7 +79,7 @@ class NLA_MT_view(bpy.types.Menu): layout.operator("screen.screen_full_area") -class NLA_MT_select(bpy.types.Menu): +class NLA_MT_select(Menu): bl_label = "Select" def draw(self, context): @@ -98,7 +99,7 @@ class NLA_MT_select(bpy.types.Menu): layout.operator("nla.select_leftright", text="After Current Frame").mode = 'RIGHT' -class NLA_MT_marker(bpy.types.Menu): +class NLA_MT_marker(Menu): bl_label = "Marker" def draw(self, context): @@ -117,7 +118,7 @@ class NLA_MT_marker(bpy.types.Menu): layout.operator("marker.move", text="Grab/Move Marker") -class NLA_MT_edit(bpy.types.Menu): +class NLA_MT_edit(Menu): bl_label = "Edit" def draw(self, context): @@ -160,7 +161,7 @@ class NLA_MT_edit(bpy.types.Menu): layout.operator("nla.tweakmode_enter", text="Start Tweaking Strip Actions") -class NLA_MT_add(bpy.types.Menu): +class NLA_MT_add(Menu): bl_label = "Add" def draw(self, context): @@ -179,7 +180,7 @@ class NLA_MT_add(bpy.types.Menu): layout.operator("nla.tracks_add", text="Add Tracks Above Selected").above_selected = True -class NLA_MT_edit_transform(bpy.types.Menu): +class NLA_MT_edit_transform(Menu): bl_label = "Transform" def draw(self, context): diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py index 2088d8798f2..b0a54004765 100644 --- a/release/scripts/startup/bl_ui/space_node.py +++ b/release/scripts/startup/bl_ui/space_node.py @@ -18,9 +18,10 @@ # import bpy +from bpy.types import Header, Menu, Panel -class NODE_HT_header(bpy.types.Header): +class NODE_HT_header(Header): bl_space_type = 'NODE_EDITOR' def draw(self, context): @@ -78,7 +79,7 @@ class NODE_HT_header(bpy.types.Header): layout.template_running_jobs() -class NODE_MT_view(bpy.types.Menu): +class NODE_MT_view(Menu): bl_label = "View" def draw(self, context): @@ -107,7 +108,7 @@ class NODE_MT_view(bpy.types.Menu): layout.operator("screen.screen_full_area") -class NODE_MT_select(bpy.types.Menu): +class NODE_MT_select(Menu): bl_label = "Select" def draw(self, context): @@ -124,7 +125,7 @@ class NODE_MT_select(bpy.types.Menu): layout.operator("node.select_same_type_prev") -class NODE_MT_node(bpy.types.Menu): +class NODE_MT_node(Menu): bl_label = "Node" def draw(self, context): @@ -165,7 +166,7 @@ class NODE_MT_node(bpy.types.Menu): # Node Backdrop options -class NODE_PT_properties(bpy.types.Panel): +class NODE_PT_properties(Panel): bl_space_type = 'NODE_EDITOR' bl_region_type = 'UI' bl_label = "Backdrop" diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 1f196cbd191..004a913a463 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -18,9 +18,10 @@ # import bpy +from bpy.types import Header, Menu -class OUTLINER_HT_header(bpy.types.Header): +class OUTLINER_HT_header(Header): bl_space_type = 'OUTLINER' def draw(self, context): @@ -63,7 +64,7 @@ class OUTLINER_HT_header(bpy.types.Header): row.label(text="No Keying Set active") -class OUTLINER_MT_view(bpy.types.Menu): +class OUTLINER_MT_view(Menu): bl_label = "View" def draw(self, context): @@ -86,7 +87,7 @@ class OUTLINER_MT_view(bpy.types.Menu): layout.operator("screen.screen_full_area") -class OUTLINER_MT_search(bpy.types.Menu): +class OUTLINER_MT_search(Menu): bl_label = "Search" def draw(self, context): @@ -100,7 +101,7 @@ class OUTLINER_MT_search(bpy.types.Menu): col.prop(space, "use_filter_complete") -class OUTLINER_MT_edit_datablocks(bpy.types.Menu): +class OUTLINER_MT_edit_datablocks(Menu): bl_label = "Edit" def draw(self, context): diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 56589188d0d..f58bd7c9150 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Header, Menu, Panel def act_strip(context): @@ -27,7 +28,7 @@ def act_strip(context): return None -class SEQUENCER_HT_header(bpy.types.Header): +class SEQUENCER_HT_header(Header): bl_space_type = 'SEQUENCE_EDITOR' def draw(self, context): @@ -76,7 +77,7 @@ class SEQUENCER_HT_header(bpy.types.Header): row.prop(ed, "overlay_lock", text="", icon='LOCKED') -class SEQUENCER_MT_view_toggle(bpy.types.Menu): +class SEQUENCER_MT_view_toggle(Menu): bl_label = "View Type" def draw(self, context): @@ -87,7 +88,7 @@ class SEQUENCER_MT_view_toggle(bpy.types.Menu): layout.operator("sequencer.view_toggle").type = 'SEQUENCER_PREVIEW' -class SEQUENCER_MT_view(bpy.types.Menu): +class SEQUENCER_MT_view(Menu): bl_label = "View" def draw(self, context): @@ -129,7 +130,7 @@ class SEQUENCER_MT_view(bpy.types.Menu): layout.operator("screen.screen_full_area") -class SEQUENCER_MT_select(bpy.types.Menu): +class SEQUENCER_MT_select(Menu): bl_label = "Select" def draw(self, context): @@ -148,7 +149,7 @@ class SEQUENCER_MT_select(bpy.types.Menu): layout.operator("sequencer.select_inverse") -class SEQUENCER_MT_marker(bpy.types.Menu): +class SEQUENCER_MT_marker(Menu): bl_label = "Marker" def draw(self, context): @@ -169,7 +170,7 @@ class SEQUENCER_MT_marker(bpy.types.Menu): #layout.operator("sequencer.sound_strip_add", text="Transform Markers") # toggle, will be rna - (sseq->flag & SEQ_MARKER_TRANS) -class SEQUENCER_MT_change(bpy.types.Menu): +class SEQUENCER_MT_change(Menu): bl_label = "Change" def draw(self, context): @@ -182,7 +183,7 @@ class SEQUENCER_MT_change(bpy.types.Menu): layout.operator("sequencer.change_path", text="Path/Files") -class SEQUENCER_MT_add(bpy.types.Menu): +class SEQUENCER_MT_add(Menu): bl_label = "Add" def draw(self, context): @@ -203,7 +204,7 @@ class SEQUENCER_MT_add(bpy.types.Menu): layout.menu("SEQUENCER_MT_add_effect") -class SEQUENCER_MT_add_effect(bpy.types.Menu): +class SEQUENCER_MT_add_effect(Menu): bl_label = "Effect Strip..." def draw(self, context): @@ -229,7 +230,7 @@ class SEQUENCER_MT_add_effect(bpy.types.Menu): layout.operator("sequencer.effect_strip_add", text="Adjustment Layer").type = 'ADJUSTMENT' -class SEQUENCER_MT_strip(bpy.types.Menu): +class SEQUENCER_MT_strip(Menu): bl_label = "Strip" def draw(self, context): @@ -334,7 +335,7 @@ class SequencerButtonsPanel_Output(): return cls.has_preview(context) -class SEQUENCER_PT_edit(SequencerButtonsPanel, bpy.types.Panel): +class SEQUENCER_PT_edit(SequencerButtonsPanel, Panel): bl_label = "Edit Strip" def draw(self, context): @@ -390,7 +391,7 @@ class SEQUENCER_PT_edit(SequencerButtonsPanel, bpy.types.Panel): col.label(text="Orig Dim: %dx%d" % (elem.orig_width, elem.orig_height)) -class SEQUENCER_PT_effect(SequencerButtonsPanel, bpy.types.Panel): +class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): bl_label = "Effect Strip" @classmethod @@ -528,7 +529,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, bpy.types.Panel): col.prop(strip, "rotation_start", text="Rotation") -class SEQUENCER_PT_input(SequencerButtonsPanel, bpy.types.Panel): +class SEQUENCER_PT_input(SequencerButtonsPanel, Panel): bl_label = "Strip Input" @classmethod @@ -609,7 +610,7 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, bpy.types.Panel): col.prop(strip, "frame_offset_end", text="End") -class SEQUENCER_PT_sound(SequencerButtonsPanel, bpy.types.Panel): +class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel): bl_label = "Sound" @classmethod @@ -650,7 +651,7 @@ class SEQUENCER_PT_sound(SequencerButtonsPanel, bpy.types.Panel): col.prop(strip, "animation_offset_end", text="End") -class SEQUENCER_PT_scene(SequencerButtonsPanel, bpy.types.Panel): +class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel): bl_label = "Scene" @classmethod @@ -684,7 +685,7 @@ class SEQUENCER_PT_scene(SequencerButtonsPanel, bpy.types.Panel): layout.label(text="Original frame range: %d-%d (%d)" % (sta, end, end - sta + 1)) -class SEQUENCER_PT_filter(SequencerButtonsPanel, bpy.types.Panel): +class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel): bl_label = "Filter" @classmethod @@ -746,7 +747,7 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, bpy.types.Panel): col.prop(strip.color_balance, "invert_gain", text="Inverse") -class SEQUENCER_PT_proxy(SequencerButtonsPanel, bpy.types.Panel): +class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel): bl_label = "Proxy" @classmethod @@ -780,7 +781,7 @@ class SEQUENCER_PT_proxy(SequencerButtonsPanel, bpy.types.Panel): flow.prop(strip.proxy, "filepath") -class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, bpy.types.Panel): +class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, Panel): bl_label = "Scene Preview/Render" bl_space_type = 'SEQUENCE_EDITOR' bl_region_type = 'UI' @@ -805,7 +806,7 @@ class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, bpy.types.Panel): ''' -class SEQUENCER_PT_view(SequencerButtonsPanel_Output, bpy.types.Panel): +class SEQUENCER_PT_view(SequencerButtonsPanel_Output, Panel): bl_label = "View Settings" def draw(self, context): diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py index b787fc5cf75..f3b8b9ce221 100644 --- a/release/scripts/startup/bl_ui/space_text.py +++ b/release/scripts/startup/bl_ui/space_text.py @@ -18,9 +18,10 @@ # import bpy +from bpy.types import Header, Menu, Panel -class TEXT_HT_header(bpy.types.Header): +class TEXT_HT_header(Header): bl_space_type = 'TEXT_EDITOR' def draw(self, context): @@ -74,7 +75,7 @@ class TEXT_HT_header(bpy.types.Header): else "Text: Internal") -class TEXT_PT_properties(bpy.types.Panel): +class TEXT_PT_properties(Panel): bl_space_type = 'TEXT_EDITOR' bl_region_type = 'UI' bl_label = "Properties" @@ -105,7 +106,7 @@ class TEXT_PT_properties(bpy.types.Panel): col.prop(st, "margin_column") -class TEXT_PT_find(bpy.types.Panel): +class TEXT_PT_find(Panel): bl_space_type = 'TEXT_EDITOR' bl_region_type = 'UI' bl_label = "Find" @@ -139,7 +140,7 @@ class TEXT_PT_find(bpy.types.Panel): row.prop(st, "use_find_all", text="All") -class TEXT_MT_view(bpy.types.Menu): +class TEXT_MT_view(Menu): bl_label = "View" def draw(self, context): @@ -162,7 +163,7 @@ class TEXT_MT_view(bpy.types.Menu): ).type = 'FILE_BOTTOM' -class TEXT_MT_text(bpy.types.Menu): +class TEXT_MT_text(Menu): bl_label = "Text" def draw(self, context): @@ -194,7 +195,7 @@ class TEXT_MT_text(bpy.types.Menu): #endif -class TEXT_MT_templates(bpy.types.Menu): +class TEXT_MT_templates(Menu): bl_label = "Templates" def draw(self, context): @@ -204,7 +205,7 @@ class TEXT_MT_templates(bpy.types.Menu): ) -class TEXT_MT_edit_select(bpy.types.Menu): +class TEXT_MT_edit_select(Menu): bl_label = "Select" def draw(self, context): @@ -214,7 +215,7 @@ class TEXT_MT_edit_select(bpy.types.Menu): layout.operator("text.select_line") -class TEXT_MT_edit_markers(bpy.types.Menu): +class TEXT_MT_edit_markers(Menu): bl_label = "Markers" def draw(self, context): @@ -225,7 +226,7 @@ class TEXT_MT_edit_markers(bpy.types.Menu): layout.operator("text.previous_marker") -class TEXT_MT_format(bpy.types.Menu): +class TEXT_MT_format(Menu): bl_label = "Format" def draw(self, context): @@ -244,7 +245,7 @@ class TEXT_MT_format(bpy.types.Menu): layout.operator_menu_enum("text.convert_whitespace", "type") -class TEXT_MT_edit_to3d(bpy.types.Menu): +class TEXT_MT_edit_to3d(Menu): bl_label = "Text To 3D Object" def draw(self, context): @@ -258,7 +259,7 @@ class TEXT_MT_edit_to3d(bpy.types.Menu): ).split_lines = True -class TEXT_MT_edit(bpy.types.Menu): +class TEXT_MT_edit(Menu): bl_label = "Edit" @classmethod @@ -292,7 +293,7 @@ class TEXT_MT_edit(bpy.types.Menu): layout.menu("TEXT_MT_edit_to3d") -class TEXT_MT_toolbox(bpy.types.Menu): +class TEXT_MT_toolbox(Menu): bl_label = "" def draw(self, context): diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py index 7e62465d1ee..0b5aec7d5f2 100644 --- a/release/scripts/startup/bl_ui/space_time.py +++ b/release/scripts/startup/bl_ui/space_time.py @@ -18,9 +18,10 @@ # import bpy +from bpy.types import Header, Menu -class TIME_HT_header(bpy.types.Header): +class TIME_HT_header(Header): bl_space_type = 'TIMELINE' def draw(self, context): @@ -91,7 +92,7 @@ class TIME_HT_header(bpy.types.Header): row.operator("anim.keyframe_delete", text="", icon='KEY_DEHLT') -class TIME_MT_view(bpy.types.Menu): +class TIME_MT_view(Menu): bl_label = "View" def draw(self, context): @@ -116,7 +117,7 @@ class TIME_MT_view(bpy.types.Menu): layout.operator("marker.camera_bind") -class TIME_MT_cache(bpy.types.Menu): +class TIME_MT_cache(Menu): bl_label = "Cache" def draw(self, context): @@ -136,7 +137,7 @@ class TIME_MT_cache(bpy.types.Menu): col.prop(st, "cache_smoke") -class TIME_MT_frame(bpy.types.Menu): +class TIME_MT_frame(Menu): bl_label = "Frame" def draw(self, context): @@ -162,7 +163,7 @@ class TIME_MT_frame(bpy.types.Menu): sub.menu("TIME_MT_autokey") -class TIME_MT_playback(bpy.types.Menu): +class TIME_MT_playback(Menu): bl_label = "Playback" def draw(self, context): @@ -187,7 +188,7 @@ class TIME_MT_playback(bpy.types.Menu): layout.prop(scene, "use_audio_scrub") -class TIME_MT_autokey(bpy.types.Menu): +class TIME_MT_autokey(Menu): bl_label = "Auto-Keyframing Mode" def draw(self, context): diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 944f5aaf4c1..148338368fe 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Header, Menu, Operator, Panel import os import addon_utils @@ -75,7 +76,7 @@ def opengl_lamp_buttons(column, lamp): col.prop(lamp, "direction", text="") -class USERPREF_HT_header(bpy.types.Header): +class USERPREF_HT_header(Header): bl_space_type = 'USER_PREFERENCES' def draw(self, context): @@ -99,7 +100,7 @@ class USERPREF_HT_header(bpy.types.Header): layout.operator("ui.reset_default_theme") -class USERPREF_PT_tabs(bpy.types.Panel): +class USERPREF_PT_tabs(Panel): bl_label = "" bl_space_type = 'USER_PREFERENCES' bl_region_type = 'WINDOW' @@ -113,14 +114,14 @@ class USERPREF_PT_tabs(bpy.types.Panel): layout.prop(userpref, "active_section", expand=True) -class USERPREF_MT_interaction_presets(bpy.types.Menu): +class USERPREF_MT_interaction_presets(Menu): bl_label = "Presets" preset_subdir = "interaction" preset_operator = "script.execute_preset" - draw = bpy.types.Menu.draw_preset + draw = Menu.draw_preset -class USERPREF_MT_appconfigs(bpy.types.Menu): +class USERPREF_MT_appconfigs(Menu): bl_label = "AppPresets" preset_subdir = "keyconfig" preset_operator = "wm.appconfig_activate" @@ -129,10 +130,10 @@ class USERPREF_MT_appconfigs(bpy.types.Menu): self.layout.operator("wm.appconfig_default", text="Blender (default)") # now draw the presets - bpy.types.Menu.draw_preset(self, context) + Menu.draw_preset(self, context) -class USERPREF_MT_splash(bpy.types.Menu): +class USERPREF_MT_splash(Menu): bl_label = "Splash" def draw(self, context): @@ -149,7 +150,7 @@ class USERPREF_MT_splash(bpy.types.Menu): row.menu("USERPREF_MT_appconfigs", text="Preset") -class USERPREF_PT_interface(bpy.types.Panel): +class USERPREF_PT_interface(Panel): bl_space_type = 'USER_PREFERENCES' bl_label = "Interface" bl_region_type = 'WINDOW' @@ -246,7 +247,7 @@ class USERPREF_PT_interface(bpy.types.Panel): col.prop(view, "show_splash") -class USERPREF_PT_edit(bpy.types.Panel): +class USERPREF_PT_edit(Panel): bl_space_type = 'USER_PREFERENCES' bl_label = "Edit" bl_region_type = 'WINDOW' @@ -359,7 +360,7 @@ class USERPREF_PT_edit(bpy.types.Panel): col.prop(edit, "use_duplicate_particle", text="Particle") -class USERPREF_PT_system(bpy.types.Panel): +class USERPREF_PT_system(Panel): bl_space_type = 'USER_PREFERENCES' bl_label = "System" bl_region_type = 'WINDOW' @@ -496,7 +497,7 @@ class USERPREF_PT_system(bpy.types.Panel): sub.template_color_ramp(system, "weight_color_range", expand=True) -class USERPREF_PT_theme(bpy.types.Panel): +class USERPREF_PT_theme(Panel): bl_space_type = 'USER_PREFERENCES' bl_label = "Themes" bl_region_type = 'WINDOW' @@ -679,7 +680,7 @@ class USERPREF_PT_theme(bpy.types.Panel): self._theme_generic(split, getattr(theme, theme.theme_area.lower())) -class USERPREF_PT_file(bpy.types.Panel): +class USERPREF_PT_file(Panel): bl_space_type = 'USER_PREFERENCES' bl_label = "Files" bl_region_type = 'WINDOW' @@ -755,7 +756,7 @@ class USERPREF_PT_file(bpy.types.Panel): from bl_ui.space_userpref_keymap import InputKeyMapPanel -class USERPREF_MT_ndof_settings(bpy.types.Menu): +class USERPREF_MT_ndof_settings(Menu): # accessed from the window keybindings in C (only) bl_label = "3D Mouse Settings" @@ -780,7 +781,7 @@ class USERPREF_MT_ndof_settings(bpy.types.Menu): layout.prop(input_prefs, "ndof_lock_horizon", icon='NDOF_DOM') -class USERPREF_PT_input(bpy.types.Panel, InputKeyMapPanel): +class USERPREF_PT_input(Panel, InputKeyMapPanel): bl_space_type = 'USER_PREFERENCES' bl_label = "Input" @@ -870,7 +871,7 @@ class USERPREF_PT_input(bpy.types.Panel, InputKeyMapPanel): #print("runtime", time.time() - start) -class USERPREF_MT_addons_dev_guides(bpy.types.Menu): +class USERPREF_MT_addons_dev_guides(Menu): bl_label = "Development Guides" # menu to open webpages with addons development guides @@ -881,7 +882,7 @@ class USERPREF_MT_addons_dev_guides(bpy.types.Menu): layout.operator('wm.url_open', text='How to share your addon', icon='URL').url = 'http://wiki.blender.org/index.php/Dev:Py/Sharing' -class USERPREF_PT_addons(bpy.types.Panel): +class USERPREF_PT_addons(Panel): bl_space_type = 'USER_PREFERENCES' bl_label = "Addons" bl_region_type = 'WINDOW' @@ -1071,7 +1072,7 @@ class USERPREF_PT_addons(bpy.types.Panel): row.operator("wm.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False).module = module_name -class WM_OT_addon_enable(bpy.types.Operator): +class WM_OT_addon_enable(Operator): "Enable an addon" bl_idname = "wm.addon_enable" bl_label = "Enable Add-On" @@ -1100,7 +1101,7 @@ class WM_OT_addon_enable(bpy.types.Operator): return {'CANCELLED'} -class WM_OT_addon_disable(bpy.types.Operator): +class WM_OT_addon_disable(Operator): "Disable an addon" bl_idname = "wm.addon_disable" bl_label = "Disable Add-On" @@ -1112,7 +1113,7 @@ class WM_OT_addon_disable(bpy.types.Operator): return {'FINISHED'} -class WM_OT_addon_install(bpy.types.Operator): +class WM_OT_addon_install(Operator): "Install an addon" bl_idname = "wm.addon_install" bl_label = "Install Add-On..." @@ -1258,7 +1259,7 @@ class WM_OT_addon_install(bpy.types.Operator): return {'RUNNING_MODAL'} -class WM_OT_addon_remove(bpy.types.Operator): +class WM_OT_addon_remove(Operator): "Disable an addon" bl_idname = "wm.addon_remove" bl_label = "Remove Add-On" @@ -1306,7 +1307,7 @@ class WM_OT_addon_remove(bpy.types.Operator): return wm.invoke_props_dialog(self, width=600) -class WM_OT_addon_expand(bpy.types.Operator): +class WM_OT_addon_expand(Operator): "Display more information on this add-on" bl_idname = "wm.addon_expand" bl_label = "" diff --git a/release/scripts/startup/bl_ui/space_userpref_keymap.py b/release/scripts/startup/bl_ui/space_userpref_keymap.py index f63da6551de..d595b32c710 100644 --- a/release/scripts/startup/bl_ui/space_userpref_keymap.py +++ b/release/scripts/startup/bl_ui/space_userpref_keymap.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Menu, Operator import os @@ -124,7 +125,7 @@ def _merge_keymaps(kc1, kc2): return merged_keymaps -class USERPREF_MT_keyconfigs(bpy.types.Menu): +class USERPREF_MT_keyconfigs(Menu): bl_label = "KeyPresets" preset_subdir = "keyconfig" preset_operator = "wm.keyconfig_activate" @@ -135,7 +136,7 @@ class USERPREF_MT_keyconfigs(bpy.types.Menu): props.value = "context.window_manager.keyconfigs.default" # now draw the presets - bpy.types.Menu.draw_preset(self, context) + Menu.draw_preset(self, context) class InputKeyMapPanel: @@ -232,7 +233,7 @@ class InputKeyMapPanel: flow = box.column_flow(columns=2) for pname, value in properties.bl_rna.properties.items(): if pname != "rna_type" and not properties.is_property_hidden(pname): - if isinstance(value, bpy.types.OperatorProperties): + if isinstance(value, OperatorProperties): InputKeyMapPanel.draw_kmi_properties(box, value, title=pname) else: flow.prop(properties, pname) @@ -410,7 +411,7 @@ def export_properties(prefix, properties, lines=None): for pname in properties.bl_rna.properties.keys(): if pname != "rna_type" and not properties.is_property_hidden(pname): value = getattr(properties, pname) - if isinstance(value, bpy.types.OperatorProperties): + if isinstance(value, OperatorProperties): export_properties(prefix + "." + pname, value, lines) elif properties.is_property_set(pname): value = _string_value(value) @@ -419,7 +420,7 @@ def export_properties(prefix, properties, lines=None): return lines -class WM_OT_keyconfig_test(bpy.types.Operator): +class WM_OT_keyconfig_test(Operator): "Test keyconfig for conflicts" bl_idname = "wm.keyconfig_test" bl_label = "Test Key Configuration for Conflicts" @@ -527,7 +528,7 @@ def _string_value(value): return result -class WM_OT_keyconfig_import(bpy.types.Operator): +class WM_OT_keyconfig_import(Operator): "Import key configuration from a python script" bl_idname = "wm.keyconfig_import" bl_label = "Import Key Configuration..." @@ -574,7 +575,7 @@ class WM_OT_keyconfig_import(bpy.types.Operator): # This operator is also used by interaction presets saving - AddPresetBase -class WM_OT_keyconfig_export(bpy.types.Operator): +class WM_OT_keyconfig_export(Operator): "Export key configuration to a python script" bl_idname = "wm.keyconfig_export" bl_label = "Export Key Configuration..." @@ -667,7 +668,7 @@ class WM_OT_keyconfig_export(bpy.types.Operator): return {'RUNNING_MODAL'} -class WM_OT_keymap_restore(bpy.types.Operator): +class WM_OT_keymap_restore(Operator): "Restore key map(s)" bl_idname = "wm.keymap_restore" bl_label = "Restore Key Map(s)" @@ -687,7 +688,7 @@ class WM_OT_keymap_restore(bpy.types.Operator): return {'FINISHED'} -class WM_OT_keyitem_restore(bpy.types.Operator): +class WM_OT_keyitem_restore(Operator): "Restore key map item" bl_idname = "wm.keyitem_restore" bl_label = "Restore Key Map Item" @@ -709,7 +710,7 @@ class WM_OT_keyitem_restore(bpy.types.Operator): return {'FINISHED'} -class WM_OT_keyitem_add(bpy.types.Operator): +class WM_OT_keyitem_add(Operator): "Add key map item" bl_idname = "wm.keyitem_add" bl_label = "Add Key Map Item" @@ -731,7 +732,7 @@ class WM_OT_keyitem_add(bpy.types.Operator): return {'FINISHED'} -class WM_OT_keyitem_remove(bpy.types.Operator): +class WM_OT_keyitem_remove(Operator): "Remove key map item" bl_idname = "wm.keyitem_remove" bl_label = "Remove Key Map Item" @@ -749,7 +750,7 @@ class WM_OT_keyitem_remove(bpy.types.Operator): return {'FINISHED'} -class WM_OT_keyconfig_remove(bpy.types.Operator): +class WM_OT_keyconfig_remove(Operator): "Remove key config" bl_idname = "wm.keyconfig_remove" bl_label = "Remove Key Config" diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 083c330f61d..fa22e216ec9 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -18,9 +18,10 @@ # import bpy +from bpy.types import Header, Menu, Operator, Panel -class VIEW3D_HT_header(bpy.types.Header): +class VIEW3D_HT_header(Header): bl_space_type = 'VIEW_3D' def draw(self, context): @@ -128,7 +129,7 @@ class ShowHideMenu(): layout.operator("%s.hide" % self._operator_name, text="Hide Unselected").unselected = True -class VIEW3D_MT_transform(bpy.types.Menu): +class VIEW3D_MT_transform(Menu): bl_label = "Transform" # TODO: get rid of the custom text strings? @@ -180,7 +181,7 @@ class VIEW3D_MT_transform(bpy.types.Menu): layout.operator("object.align") -class VIEW3D_MT_mirror(bpy.types.Menu): +class VIEW3D_MT_mirror(Menu): bl_label = "Mirror" def draw(self, context): @@ -218,7 +219,7 @@ class VIEW3D_MT_mirror(bpy.types.Menu): layout.operator("object.vertex_group_mirror") -class VIEW3D_MT_snap(bpy.types.Menu): +class VIEW3D_MT_snap(Menu): bl_label = "Snap" def draw(self, context): @@ -235,7 +236,7 @@ class VIEW3D_MT_snap(bpy.types.Menu): layout.operator("view3d.snap_cursor_to_active", text="Cursor to Active") -class VIEW3D_MT_uv_map(bpy.types.Menu): +class VIEW3D_MT_uv_map(Menu): bl_label = "UV Mapping" def draw(self, context): @@ -268,7 +269,7 @@ class VIEW3D_MT_uv_map(bpy.types.Menu): # ********** View menus ********** -class VIEW3D_MT_view(bpy.types.Menu): +class VIEW3D_MT_view(Menu): bl_label = "View" def draw(self, context): @@ -326,7 +327,7 @@ class VIEW3D_MT_view(bpy.types.Menu): layout.operator("screen.screen_full_area") -class VIEW3D_MT_view_navigation(bpy.types.Menu): +class VIEW3D_MT_view_navigation(Menu): bl_label = "Navigation" def draw(self, context): @@ -349,7 +350,7 @@ class VIEW3D_MT_view_navigation(bpy.types.Menu): layout.operator("view3d.fly") -class VIEW3D_MT_view_align(bpy.types.Menu): +class VIEW3D_MT_view_align(Menu): bl_label = "Align View" def draw(self, context): @@ -365,7 +366,7 @@ class VIEW3D_MT_view_align(bpy.types.Menu): layout.operator("view3d.view_center_cursor") -class VIEW3D_MT_view_align_selected(bpy.types.Menu): +class VIEW3D_MT_view_align_selected(Menu): bl_label = "Align View to Selected" def draw(self, context): @@ -391,7 +392,7 @@ class VIEW3D_MT_view_align_selected(bpy.types.Menu): props.type = 'LEFT' -class VIEW3D_MT_view_cameras(bpy.types.Menu): +class VIEW3D_MT_view_cameras(Menu): bl_label = "Cameras" def draw(self, context): @@ -403,7 +404,7 @@ class VIEW3D_MT_view_cameras(bpy.types.Menu): # ********** Select menus, suffix from context.mode ********** -class VIEW3D_MT_select_object(bpy.types.Menu): +class VIEW3D_MT_select_object(Menu): bl_label = "Select" def draw(self, context): @@ -429,7 +430,7 @@ class VIEW3D_MT_select_object(bpy.types.Menu): layout.operator("object.select_pattern", text="Select Pattern...") -class VIEW3D_MT_select_pose(bpy.types.Menu): +class VIEW3D_MT_select_pose(Menu): bl_label = "Select" def draw(self, context): @@ -466,7 +467,7 @@ class VIEW3D_MT_select_pose(bpy.types.Menu): layout.operator("object.select_pattern", text="Select Pattern...") -class VIEW3D_MT_select_particle(bpy.types.Menu): +class VIEW3D_MT_select_particle(Menu): bl_label = "Select" def draw(self, context): @@ -491,7 +492,7 @@ class VIEW3D_MT_select_particle(bpy.types.Menu): layout.operator("particle.select_tips", text="Tips") -class VIEW3D_MT_select_edit_mesh(bpy.types.Menu): +class VIEW3D_MT_select_edit_mesh(Menu): bl_label = "Select" def draw(self, context): @@ -543,7 +544,7 @@ class VIEW3D_MT_select_edit_mesh(bpy.types.Menu): layout.operator("mesh.region_to_loop") -class VIEW3D_MT_select_edit_curve(bpy.types.Menu): +class VIEW3D_MT_select_edit_curve(Menu): bl_label = "Select" def draw(self, context): @@ -572,7 +573,7 @@ class VIEW3D_MT_select_edit_curve(bpy.types.Menu): layout.operator("curve.select_less") -class VIEW3D_MT_select_edit_surface(bpy.types.Menu): +class VIEW3D_MT_select_edit_surface(Menu): bl_label = "Select" def draw(self, context): @@ -598,7 +599,7 @@ class VIEW3D_MT_select_edit_surface(bpy.types.Menu): layout.operator("curve.select_less") -class VIEW3D_MT_select_edit_metaball(bpy.types.Menu): +class VIEW3D_MT_select_edit_metaball(Menu): bl_label = "Select" def draw(self, context): @@ -616,7 +617,7 @@ class VIEW3D_MT_select_edit_metaball(bpy.types.Menu): layout.operator("mball.select_random_metaelems") -class VIEW3D_MT_select_edit_lattice(bpy.types.Menu): +class VIEW3D_MT_select_edit_lattice(Menu): bl_label = "Select" def draw(self, context): @@ -629,7 +630,7 @@ class VIEW3D_MT_select_edit_lattice(bpy.types.Menu): layout.operator("lattice.select_all", text="Select/Deselect All") -class VIEW3D_MT_select_edit_armature(bpy.types.Menu): +class VIEW3D_MT_select_edit_armature(Menu): bl_label = "Select" def draw(self, context): @@ -660,7 +661,7 @@ class VIEW3D_MT_select_edit_armature(bpy.types.Menu): layout.operator("object.select_pattern", text="Select Pattern...") -class VIEW3D_MT_select_face(bpy.types.Menu): # XXX no matching enum +class VIEW3D_MT_select_face(Menu): # XXX no matching enum bl_label = "Select" def draw(self, context): @@ -673,7 +674,7 @@ class VIEW3D_MT_select_face(bpy.types.Menu): # XXX no matching enum # ********** Object menu ********** -class VIEW3D_MT_object(bpy.types.Menu): +class VIEW3D_MT_object(Menu): bl_context = "objectmode" bl_label = "Object" @@ -731,7 +732,7 @@ class VIEW3D_MT_object(bpy.types.Menu): layout.operator_menu_enum("object.convert", "target") -class VIEW3D_MT_object_animation(bpy.types.Menu): +class VIEW3D_MT_object_animation(Menu): bl_label = "Animation" def draw(self, context): @@ -742,7 +743,7 @@ class VIEW3D_MT_object_animation(bpy.types.Menu): layout.operator("anim.keying_set_active_set", text="Change Keying Set...") -class VIEW3D_MT_object_clear(bpy.types.Menu): +class VIEW3D_MT_object_clear(Menu): bl_label = "Clear" def draw(self, context): @@ -754,7 +755,7 @@ class VIEW3D_MT_object_clear(bpy.types.Menu): layout.operator("object.origin_clear", text="Origin") -class VIEW3D_MT_object_specials(bpy.types.Menu): +class VIEW3D_MT_object_specials(Menu): bl_label = "Specials" @classmethod @@ -849,7 +850,7 @@ class VIEW3D_MT_object_specials(bpy.types.Menu): props = layout.operator("object.hide_render_clear_all") -class VIEW3D_MT_object_apply(bpy.types.Menu): +class VIEW3D_MT_object_apply(Menu): bl_label = "Apply" def draw(self, context): @@ -868,7 +869,7 @@ class VIEW3D_MT_object_apply(bpy.types.Menu): layout.operator("object.duplicates_make_real") -class VIEW3D_MT_object_parent(bpy.types.Menu): +class VIEW3D_MT_object_parent(Menu): bl_label = "Parent" def draw(self, context): @@ -878,7 +879,7 @@ class VIEW3D_MT_object_parent(bpy.types.Menu): layout.operator("object.parent_clear", text="Clear") -class VIEW3D_MT_object_track(bpy.types.Menu): +class VIEW3D_MT_object_track(Menu): bl_label = "Track" def draw(self, context): @@ -888,7 +889,7 @@ class VIEW3D_MT_object_track(bpy.types.Menu): layout.operator("object.track_clear", text="Clear") -class VIEW3D_MT_object_group(bpy.types.Menu): +class VIEW3D_MT_object_group(Menu): bl_label = "Group" def draw(self, context): @@ -903,7 +904,7 @@ class VIEW3D_MT_object_group(bpy.types.Menu): layout.operator("group.objects_remove_active") -class VIEW3D_MT_object_constraints(bpy.types.Menu): +class VIEW3D_MT_object_constraints(Menu): bl_label = "Constraints" def draw(self, context): @@ -914,7 +915,7 @@ class VIEW3D_MT_object_constraints(bpy.types.Menu): layout.operator("object.constraints_clear") -class VIEW3D_MT_object_showhide(bpy.types.Menu): +class VIEW3D_MT_object_showhide(Menu): bl_label = "Show/Hide" def draw(self, context): @@ -925,7 +926,7 @@ class VIEW3D_MT_object_showhide(bpy.types.Menu): layout.operator("object.hide_view_set", text="Hide Unselected").unselected = True -class VIEW3D_MT_make_single_user(bpy.types.Menu): +class VIEW3D_MT_make_single_user(Menu): bl_label = "Make Single User" def draw(self, context): @@ -947,7 +948,7 @@ class VIEW3D_MT_make_single_user(bpy.types.Menu): props.animation = True -class VIEW3D_MT_make_links(bpy.types.Menu): +class VIEW3D_MT_make_links(Menu): bl_label = "Make Links" def draw(self, context): @@ -964,7 +965,7 @@ class VIEW3D_MT_make_links(bpy.types.Menu): layout.operator_enum("object.make_links_data", "type") # inline -class VIEW3D_MT_object_game(bpy.types.Menu): +class VIEW3D_MT_object_game(Menu): bl_label = "Game" def draw(self, context): @@ -986,7 +987,7 @@ class VIEW3D_MT_object_game(bpy.types.Menu): # ********** Vertex paint menu ********** -class VIEW3D_MT_paint_vertex(bpy.types.Menu): +class VIEW3D_MT_paint_vertex(Menu): bl_label = "Paint" def draw(self, context): @@ -1001,7 +1002,7 @@ class VIEW3D_MT_paint_vertex(bpy.types.Menu): layout.operator("paint.vertex_color_dirt") -class VIEW3D_MT_hook(bpy.types.Menu): +class VIEW3D_MT_hook(Menu): bl_label = "Hooks" def draw(self, context): @@ -1020,7 +1021,7 @@ class VIEW3D_MT_hook(bpy.types.Menu): layout.operator_menu_enum("object.hook_recenter", "modifier") -class VIEW3D_MT_vertex_group(bpy.types.Menu): +class VIEW3D_MT_vertex_group(Menu): bl_label = "Vertex Groups" def draw(self, context): @@ -1045,7 +1046,7 @@ class VIEW3D_MT_vertex_group(bpy.types.Menu): # ********** Weight paint menu ********** -class VIEW3D_MT_paint_weight(bpy.types.Menu): +class VIEW3D_MT_paint_weight(Menu): bl_label = "Weights" def draw(self, context): @@ -1075,7 +1076,7 @@ class VIEW3D_MT_paint_weight(bpy.types.Menu): # ********** Sculpt menu ********** -class VIEW3D_MT_sculpt(bpy.types.Menu): +class VIEW3D_MT_sculpt(Menu): bl_label = "Sculpt" def draw(self, context): @@ -1125,7 +1126,7 @@ class VIEW3D_MT_sculpt(bpy.types.Menu): # ********** Particle menu ********** -class VIEW3D_MT_particle(bpy.types.Menu): +class VIEW3D_MT_particle(Menu): bl_label = "Particle" def draw(self, context): @@ -1157,7 +1158,7 @@ class VIEW3D_MT_particle(bpy.types.Menu): layout.menu("VIEW3D_MT_particle_showhide") -class VIEW3D_MT_particle_specials(bpy.types.Menu): +class VIEW3D_MT_particle_specials(Menu): bl_label = "Specials" def draw(self, context): @@ -1175,13 +1176,13 @@ class VIEW3D_MT_particle_specials(bpy.types.Menu): layout.operator("particle.remove_doubles") -class VIEW3D_MT_particle_showhide(ShowHideMenu, bpy.types.Menu): +class VIEW3D_MT_particle_showhide(ShowHideMenu, Menu): _operator_name = "particle" # ********** Pose Menu ********** -class VIEW3D_MT_pose(bpy.types.Menu): +class VIEW3D_MT_pose(Menu): bl_label = "Pose" def draw(self, context): @@ -1250,7 +1251,7 @@ class VIEW3D_MT_pose(bpy.types.Menu): layout.menu("VIEW3D_MT_bone_options_toggle", text="Bone Settings") -class VIEW3D_MT_pose_transform(bpy.types.Menu): +class VIEW3D_MT_pose_transform(Menu): bl_label = "Clear Transform" def draw(self, context): @@ -1265,7 +1266,7 @@ class VIEW3D_MT_pose_transform(bpy.types.Menu): layout.label(text="Origin") -class VIEW3D_MT_pose_slide(bpy.types.Menu): +class VIEW3D_MT_pose_slide(Menu): bl_label = "In-Betweens" def draw(self, context): @@ -1276,7 +1277,7 @@ class VIEW3D_MT_pose_slide(bpy.types.Menu): layout.operator("pose.breakdown") -class VIEW3D_MT_pose_propagate(bpy.types.Menu): +class VIEW3D_MT_pose_propagate(Menu): bl_label = "Propagate" def draw(self, context): @@ -1294,7 +1295,7 @@ class VIEW3D_MT_pose_propagate(bpy.types.Menu): layout.operator("pose.propagate", text="On Selected Markers").mode = 'SELECTED_MARKERS' -class VIEW3D_MT_pose_library(bpy.types.Menu): +class VIEW3D_MT_pose_library(Menu): bl_label = "Pose Library" def draw(self, context): @@ -1309,7 +1310,7 @@ class VIEW3D_MT_pose_library(bpy.types.Menu): layout.operator("poselib.pose_remove", text="Remove Pose...") -class VIEW3D_MT_pose_motion(bpy.types.Menu): +class VIEW3D_MT_pose_motion(Menu): bl_label = "Motion Paths" def draw(self, context): @@ -1319,7 +1320,7 @@ class VIEW3D_MT_pose_motion(bpy.types.Menu): layout.operator("pose.paths_clear", text="Clear") -class VIEW3D_MT_pose_group(bpy.types.Menu): +class VIEW3D_MT_pose_group(Menu): bl_label = "Bone Groups" def draw(self, context): @@ -1333,7 +1334,7 @@ class VIEW3D_MT_pose_group(bpy.types.Menu): layout.operator("pose.group_unassign") -class VIEW3D_MT_pose_ik(bpy.types.Menu): +class VIEW3D_MT_pose_ik(Menu): bl_label = "Inverse Kinematics" def draw(self, context): @@ -1343,7 +1344,7 @@ class VIEW3D_MT_pose_ik(bpy.types.Menu): layout.operator("pose.ik_clear") -class VIEW3D_MT_pose_constraints(bpy.types.Menu): +class VIEW3D_MT_pose_constraints(Menu): bl_label = "Constraints" def draw(self, context): @@ -1354,11 +1355,11 @@ class VIEW3D_MT_pose_constraints(bpy.types.Menu): layout.operator("pose.constraints_clear") -class VIEW3D_MT_pose_showhide(ShowHideMenu, bpy.types.Menu): +class VIEW3D_MT_pose_showhide(ShowHideMenu, Menu): _operator_name = "pose" -class VIEW3D_MT_pose_apply(bpy.types.Menu): +class VIEW3D_MT_pose_apply(Menu): bl_label = "Apply" def draw(self, context): @@ -1397,24 +1398,24 @@ class BoneOptions: props.type = self.type -class VIEW3D_MT_bone_options_toggle(bpy.types.Menu, BoneOptions): +class VIEW3D_MT_bone_options_toggle(Menu, BoneOptions): bl_label = "Toggle Bone Options" type = 'TOGGLE' -class VIEW3D_MT_bone_options_enable(bpy.types.Menu, BoneOptions): +class VIEW3D_MT_bone_options_enable(Menu, BoneOptions): bl_label = "Enable Bone Options" type = 'ENABLE' -class VIEW3D_MT_bone_options_disable(bpy.types.Menu, BoneOptions): +class VIEW3D_MT_bone_options_disable(Menu, BoneOptions): bl_label = "Disable Bone Options" type = 'DISABLE' # ********** Edit Menus, suffix from ob.type ********** -class VIEW3D_MT_edit_mesh(bpy.types.Menu): +class VIEW3D_MT_edit_mesh(Menu): bl_label = "Mesh" def draw(self, context): @@ -1461,7 +1462,7 @@ class VIEW3D_MT_edit_mesh(bpy.types.Menu): layout.menu("VIEW3D_MT_edit_mesh_showhide") -class VIEW3D_MT_edit_mesh_specials(bpy.types.Menu): +class VIEW3D_MT_edit_mesh_specials(Menu): bl_label = "Specials" def draw(self, context): @@ -1486,7 +1487,7 @@ class VIEW3D_MT_edit_mesh_specials(bpy.types.Menu): layout.operator("mesh.select_vertex_path") -class VIEW3D_MT_edit_mesh_select_mode(bpy.types.Menu): +class VIEW3D_MT_edit_mesh_select_mode(Menu): bl_label = "Mesh Select Mode" def draw(self, context): @@ -1507,7 +1508,7 @@ class VIEW3D_MT_edit_mesh_select_mode(bpy.types.Menu): prop.data_path = "tool_settings.mesh_select_mode" -class VIEW3D_MT_edit_mesh_extrude(bpy.types.Menu): +class VIEW3D_MT_edit_mesh_extrude(Menu): bl_label = "Extrude" _extrude_funcs = { \ @@ -1541,7 +1542,7 @@ class VIEW3D_MT_edit_mesh_extrude(bpy.types.Menu): self._extrude_funcs[menu_id](layout) -class VIEW3D_OT_edit_mesh_extrude_individual_move(bpy.types.Operator): +class VIEW3D_OT_edit_mesh_extrude_individual_move(Operator): "Extrude individual elements and move" bl_label = "Extrude Individual and Move" bl_idname = "view3d.edit_mesh_extrude_individual_move" @@ -1570,7 +1571,7 @@ class VIEW3D_OT_edit_mesh_extrude_individual_move(bpy.types.Operator): return self.execute(context) -class VIEW3D_OT_edit_mesh_extrude_move(bpy.types.Operator): +class VIEW3D_OT_edit_mesh_extrude_move(Operator): "Extrude and move along normals" bl_label = "Extrude and Move on Normals" bl_idname = "view3d.edit_mesh_extrude_move_normal" @@ -1596,7 +1597,7 @@ class VIEW3D_OT_edit_mesh_extrude_move(bpy.types.Operator): return self.execute(context) -class VIEW3D_MT_edit_mesh_vertices(bpy.types.Menu): +class VIEW3D_MT_edit_mesh_vertices(Menu): bl_label = "Vertices" def draw(self, context): @@ -1628,7 +1629,7 @@ class VIEW3D_MT_edit_mesh_vertices(bpy.types.Menu): layout.menu("VIEW3D_MT_hook") -class VIEW3D_MT_edit_mesh_edges(bpy.types.Menu): +class VIEW3D_MT_edit_mesh_edges(Menu): bl_label = "Edges" def draw(self, context): @@ -1668,7 +1669,7 @@ class VIEW3D_MT_edit_mesh_edges(bpy.types.Menu): layout.operator("mesh.region_to_loop") -class VIEW3D_MT_edit_mesh_faces(bpy.types.Menu): +class VIEW3D_MT_edit_mesh_faces(Menu): bl_label = "Faces" bl_idname = "VIEW3D_MT_edit_mesh_faces" @@ -1716,7 +1717,7 @@ class VIEW3D_MT_edit_mesh_faces(bpy.types.Menu): layout.operator_menu_enum("mesh.colors_mirror", "axis") -class VIEW3D_MT_edit_mesh_normals(bpy.types.Menu): +class VIEW3D_MT_edit_mesh_normals(Menu): bl_label = "Normals" def draw(self, context): @@ -1730,7 +1731,7 @@ class VIEW3D_MT_edit_mesh_normals(bpy.types.Menu): layout.operator("mesh.flip_normals") -class VIEW3D_MT_edit_mesh_showhide(ShowHideMenu, bpy.types.Menu): +class VIEW3D_MT_edit_mesh_showhide(ShowHideMenu, Menu): _operator_name = "mesh" # Edit Curve @@ -1770,13 +1771,13 @@ def draw_curve(self, context): layout.menu("VIEW3D_MT_edit_curve_showhide") -class VIEW3D_MT_edit_curve(bpy.types.Menu): +class VIEW3D_MT_edit_curve(Menu): bl_label = "Curve" draw = draw_curve -class VIEW3D_MT_edit_curve_ctrlpoints(bpy.types.Menu): +class VIEW3D_MT_edit_curve_ctrlpoints(Menu): bl_label = "Control Points" def draw(self, context): @@ -1798,7 +1799,7 @@ class VIEW3D_MT_edit_curve_ctrlpoints(bpy.types.Menu): layout.menu("VIEW3D_MT_hook") -class VIEW3D_MT_edit_curve_segments(bpy.types.Menu): +class VIEW3D_MT_edit_curve_segments(Menu): bl_label = "Segments" def draw(self, context): @@ -1808,7 +1809,7 @@ class VIEW3D_MT_edit_curve_segments(bpy.types.Menu): layout.operator("curve.switch_direction") -class VIEW3D_MT_edit_curve_specials(bpy.types.Menu): +class VIEW3D_MT_edit_curve_specials(Menu): bl_label = "Specials" def draw(self, context): @@ -1822,17 +1823,17 @@ class VIEW3D_MT_edit_curve_specials(bpy.types.Menu): layout.operator("curve.smooth_radius") -class VIEW3D_MT_edit_curve_showhide(ShowHideMenu, bpy.types.Menu): +class VIEW3D_MT_edit_curve_showhide(ShowHideMenu, Menu): _operator_name = "curve" -class VIEW3D_MT_edit_surface(bpy.types.Menu): +class VIEW3D_MT_edit_surface(Menu): bl_label = "Surface" draw = draw_curve -class VIEW3D_MT_edit_font(bpy.types.Menu): +class VIEW3D_MT_edit_font(Menu): bl_label = "Text" def draw(self, context): @@ -1852,7 +1853,7 @@ class VIEW3D_MT_edit_font(bpy.types.Menu): layout.operator("font.style_toggle", text="Toggle Small Caps").style = 'SMALL_CAPS' -class VIEW3D_MT_edit_text_chars(bpy.types.Menu): +class VIEW3D_MT_edit_text_chars(Menu): bl_label = "Special Characters" def draw(self, context): @@ -1886,7 +1887,7 @@ class VIEW3D_MT_edit_text_chars(bpy.types.Menu): layout.operator("font.text_insert", text="Spanish Exclamation Mark|Alt !").text = b'\xC2\xA1'.decode() -class VIEW3D_MT_edit_meta(bpy.types.Menu): +class VIEW3D_MT_edit_meta(Menu): bl_label = "Metaball" def draw(self, context): @@ -1919,7 +1920,7 @@ class VIEW3D_MT_edit_meta(bpy.types.Menu): layout.menu("VIEW3D_MT_edit_meta_showhide") -class VIEW3D_MT_edit_meta_showhide(bpy.types.Menu): +class VIEW3D_MT_edit_meta_showhide(Menu): bl_label = "Show/Hide" def draw(self, context): @@ -1930,7 +1931,7 @@ class VIEW3D_MT_edit_meta_showhide(bpy.types.Menu): layout.operator("mball.hide_metaelems", text="Hide Unselected").unselected = True -class VIEW3D_MT_edit_lattice(bpy.types.Menu): +class VIEW3D_MT_edit_lattice(Menu): bl_label = "Lattice" def draw(self, context): @@ -1952,7 +1953,7 @@ class VIEW3D_MT_edit_lattice(bpy.types.Menu): layout.prop_menu_enum(settings, "proportional_edit_falloff") -class VIEW3D_MT_edit_armature(bpy.types.Menu): +class VIEW3D_MT_edit_armature(Menu): bl_label = "Armature" def draw(self, context): @@ -2007,7 +2008,7 @@ class VIEW3D_MT_edit_armature(bpy.types.Menu): layout.menu("VIEW3D_MT_bone_options_toggle", text="Bone Settings") -class VIEW3D_MT_armature_specials(bpy.types.Menu): +class VIEW3D_MT_armature_specials(Menu): bl_label = "Specials" def draw(self, context): @@ -2027,7 +2028,7 @@ class VIEW3D_MT_armature_specials(bpy.types.Menu): layout.operator("armature.flip_names", text="Flip Names") -class VIEW3D_MT_edit_armature_parent(bpy.types.Menu): +class VIEW3D_MT_edit_armature_parent(Menu): bl_label = "Parent" def draw(self, context): @@ -2037,7 +2038,7 @@ class VIEW3D_MT_edit_armature_parent(bpy.types.Menu): layout.operator("armature.parent_clear", text="Clear") -class VIEW3D_MT_edit_armature_roll(bpy.types.Menu): +class VIEW3D_MT_edit_armature_roll(Menu): bl_label = "Bone Roll" def draw(self, context): @@ -2052,7 +2053,7 @@ class VIEW3D_MT_edit_armature_roll(bpy.types.Menu): # ********** Panel ********** -class VIEW3D_PT_view3d_properties(bpy.types.Panel): +class VIEW3D_PT_view3d_properties(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_label = "View" @@ -2093,7 +2094,7 @@ class VIEW3D_PT_view3d_properties(bpy.types.Panel): layout.column().prop(view, "cursor_location") -class VIEW3D_PT_view3d_name(bpy.types.Panel): +class VIEW3D_PT_view3d_name(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_label = "Item" @@ -2118,7 +2119,7 @@ class VIEW3D_PT_view3d_name(bpy.types.Panel): row.prop(bone, "name", text="") -class VIEW3D_PT_view3d_display(bpy.types.Panel): +class VIEW3D_PT_view3d_display(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_label = "Display" @@ -2190,7 +2191,7 @@ class VIEW3D_PT_view3d_display(bpy.types.Panel): row.prop(region, "use_box_clip") -class VIEW3D_PT_view3d_meshdisplay(bpy.types.Panel): +class VIEW3D_PT_view3d_meshdisplay(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_label = "Mesh Display" @@ -2227,7 +2228,7 @@ class VIEW3D_PT_view3d_meshdisplay(bpy.types.Panel): col.prop(mesh, "show_extra_face_area") -class VIEW3D_PT_view3d_curvedisplay(bpy.types.Panel): +class VIEW3D_PT_view3d_curvedisplay(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_label = "Curve Display" @@ -2249,7 +2250,7 @@ class VIEW3D_PT_view3d_curvedisplay(bpy.types.Panel): col.prop(context.scene.tool_settings, "normal_size", text="Normal Size") -class VIEW3D_PT_background_image(bpy.types.Panel): +class VIEW3D_PT_background_image(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_label = "Background Images" @@ -2302,7 +2303,7 @@ class VIEW3D_PT_background_image(bpy.types.Panel): row.prop(bg, "offset_y", text="Y") -class VIEW3D_PT_transform_orientations(bpy.types.Panel): +class VIEW3D_PT_transform_orientations(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_label = "Transform Orientations" @@ -2330,7 +2331,7 @@ class VIEW3D_PT_transform_orientations(bpy.types.Panel): col.operator("transform.delete_orientation", text="Delete") -class VIEW3D_PT_etch_a_ton(bpy.types.Panel): +class VIEW3D_PT_etch_a_ton(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_label = "Skeleton Sketching" @@ -2375,7 +2376,7 @@ class VIEW3D_PT_etch_a_ton(bpy.types.Panel): col.operator("sketch.convert", text="Convert") -class VIEW3D_PT_context_properties(bpy.types.Panel): +class VIEW3D_PT_context_properties(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_label = "Properties" diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 85dd6f7da5e..864d59f0cdb 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -18,6 +18,7 @@ # import bpy +from bpy.types import Menu, Panel class View3DPanel(): @@ -61,7 +62,7 @@ def draw_gpencil_tools(context, layout): # ********** default tools for objectmode **************** -class VIEW3D_PT_tools_objectmode(View3DPanel, bpy.types.Panel): +class VIEW3D_PT_tools_objectmode(View3DPanel, Panel): bl_context = "objectmode" bl_label = "Object Tools" @@ -106,7 +107,7 @@ class VIEW3D_PT_tools_objectmode(View3DPanel, bpy.types.Panel): # ********** default tools for editmode_mesh **************** -class VIEW3D_PT_tools_meshedit(View3DPanel, bpy.types.Panel): +class VIEW3D_PT_tools_meshedit(View3DPanel, Panel): bl_context = "mesh_edit" bl_label = "Mesh Tools" @@ -165,7 +166,7 @@ class VIEW3D_PT_tools_meshedit(View3DPanel, bpy.types.Panel): draw_gpencil_tools(context, layout) -class VIEW3D_PT_tools_meshedit_options(View3DPanel, bpy.types.Panel): +class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel): bl_context = "mesh_edit" bl_label = "Mesh Options" @@ -191,7 +192,7 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, bpy.types.Panel): # ********** default tools for editmode_curve **************** -class VIEW3D_PT_tools_curveedit(View3DPanel, bpy.types.Panel): +class VIEW3D_PT_tools_curveedit(View3DPanel, Panel): bl_context = "curve_edit" bl_label = "Curve Tools" @@ -237,7 +238,7 @@ class VIEW3D_PT_tools_curveedit(View3DPanel, bpy.types.Panel): # ********** default tools for editmode_surface **************** -class VIEW3D_PT_tools_surfaceedit(View3DPanel, bpy.types.Panel): +class VIEW3D_PT_tools_surfaceedit(View3DPanel, Panel): bl_context = "surface_edit" bl_label = "Surface Tools" @@ -269,7 +270,7 @@ class VIEW3D_PT_tools_surfaceedit(View3DPanel, bpy.types.Panel): # ********** default tools for editmode_text **************** -class VIEW3D_PT_tools_textedit(View3DPanel, bpy.types.Panel): +class VIEW3D_PT_tools_textedit(View3DPanel, Panel): bl_context = "text_edit" bl_label = "Text Tools" @@ -299,7 +300,7 @@ class VIEW3D_PT_tools_textedit(View3DPanel, bpy.types.Panel): # ********** default tools for editmode_armature **************** -class VIEW3D_PT_tools_armatureedit(View3DPanel, bpy.types.Panel): +class VIEW3D_PT_tools_armatureedit(View3DPanel, Panel): bl_context = "armature_edit" bl_label = "Armature Tools" @@ -328,7 +329,7 @@ class VIEW3D_PT_tools_armatureedit(View3DPanel, bpy.types.Panel): draw_gpencil_tools(context, layout) -class VIEW3D_PT_tools_armatureedit_options(View3DPanel, bpy.types.Panel): +class VIEW3D_PT_tools_armatureedit_options(View3DPanel, Panel): bl_context = "armature_edit" bl_label = "Armature Options" @@ -340,7 +341,7 @@ class VIEW3D_PT_tools_armatureedit_options(View3DPanel, bpy.types.Panel): # ********** default tools for editmode_mball **************** -class VIEW3D_PT_tools_mballedit(View3DPanel, bpy.types.Panel): +class VIEW3D_PT_tools_mballedit(View3DPanel, Panel): bl_context = "mball_edit" bl_label = "Meta Tools" @@ -360,7 +361,7 @@ class VIEW3D_PT_tools_mballedit(View3DPanel, bpy.types.Panel): # ********** default tools for editmode_lattice **************** -class VIEW3D_PT_tools_latticeedit(View3DPanel, bpy.types.Panel): +class VIEW3D_PT_tools_latticeedit(View3DPanel, Panel): bl_context = "lattice_edit" bl_label = "Lattice Tools" @@ -384,7 +385,7 @@ class VIEW3D_PT_tools_latticeedit(View3DPanel, bpy.types.Panel): # ********** default tools for posemode **************** -class VIEW3D_PT_tools_posemode(View3DPanel, bpy.types.Panel): +class VIEW3D_PT_tools_posemode(View3DPanel, Panel): bl_context = "posemode" bl_label = "Pose Tools" @@ -425,7 +426,7 @@ class VIEW3D_PT_tools_posemode(View3DPanel, bpy.types.Panel): draw_gpencil_tools(context, layout) -class VIEW3D_PT_tools_posemode_options(View3DPanel, bpy.types.Panel): +class VIEW3D_PT_tools_posemode_options(View3DPanel, Panel): bl_context = "posemode" bl_label = "Pose Options" @@ -459,7 +460,7 @@ class PaintPanel(): return None -class VIEW3D_PT_tools_brush(PaintPanel, bpy.types.Panel): +class VIEW3D_PT_tools_brush(PaintPanel, Panel): bl_label = "Brush" @classmethod @@ -677,7 +678,7 @@ class VIEW3D_PT_tools_brush(PaintPanel, bpy.types.Panel): #row.prop(brush, "use_pressure_jitter", toggle=True, text="") -class VIEW3D_PT_tools_brush_texture(PaintPanel, bpy.types.Panel): +class VIEW3D_PT_tools_brush_texture(PaintPanel, Panel): bl_label = "Texture" bl_options = {'DEFAULT_CLOSED'} @@ -775,7 +776,7 @@ class VIEW3D_PT_tools_brush_texture(PaintPanel, bpy.types.Panel): col.active = tex_slot.map_mode in {'FIXED', 'TILED'} and brush.use_texture_overlay -class VIEW3D_PT_tools_brush_tool(PaintPanel, bpy.types.Panel): +class VIEW3D_PT_tools_brush_tool(PaintPanel, Panel): bl_label = "Tool" bl_options = {'DEFAULT_CLOSED'} @@ -809,7 +810,7 @@ class VIEW3D_PT_tools_brush_tool(PaintPanel, bpy.types.Panel): row.prop(brush, "use_paint_image", text="", icon='TPAINT_HLT') -class VIEW3D_PT_tools_brush_stroke(PaintPanel, bpy.types.Panel): +class VIEW3D_PT_tools_brush_stroke(PaintPanel, Panel): bl_label = "Stroke" bl_options = {'DEFAULT_CLOSED'} @@ -907,7 +908,7 @@ class VIEW3D_PT_tools_brush_stroke(PaintPanel, bpy.types.Panel): # row.prop(brush, "use_pressure_spacing", toggle=True, text="") -class VIEW3D_PT_tools_brush_curve(PaintPanel, bpy.types.Panel): +class VIEW3D_PT_tools_brush_curve(PaintPanel, Panel): bl_label = "Curve" bl_options = {'DEFAULT_CLOSED'} @@ -934,7 +935,7 @@ class VIEW3D_PT_tools_brush_curve(PaintPanel, bpy.types.Panel): row.operator("brush.curve_preset", icon="NOCURVE", text="").shape = 'MAX' -class VIEW3D_PT_sculpt_options(PaintPanel, bpy.types.Panel): +class VIEW3D_PT_sculpt_options(PaintPanel, Panel): bl_label = "Options" bl_options = {'DEFAULT_CLOSED'} @@ -964,7 +965,7 @@ class VIEW3D_PT_sculpt_options(PaintPanel, bpy.types.Panel): layout.prop(tool_settings, "sculpt_paint_use_unified_strength", text="Strength") -class VIEW3D_PT_sculpt_symmetry(PaintPanel, bpy.types.Panel): +class VIEW3D_PT_sculpt_symmetry(PaintPanel, Panel): bl_label = "Symmetry" bl_options = {'DEFAULT_CLOSED'} @@ -992,7 +993,7 @@ class VIEW3D_PT_sculpt_symmetry(PaintPanel, bpy.types.Panel): layout.prop(sculpt, "use_symmetry_feather", text="Feather") -class VIEW3D_PT_tools_brush_appearance(PaintPanel, bpy.types.Panel): +class VIEW3D_PT_tools_brush_appearance(PaintPanel, Panel): bl_label = "Appearance" bl_options = {'DEFAULT_CLOSED'} @@ -1038,7 +1039,7 @@ class VIEW3D_PT_tools_brush_appearance(PaintPanel, bpy.types.Panel): # ********** default tools for weightpaint **************** -class VIEW3D_PT_tools_weightpaint(View3DPanel, bpy.types.Panel): +class VIEW3D_PT_tools_weightpaint(View3DPanel, Panel): bl_context = "weightpaint" bl_label = "Weight Tools" @@ -1056,7 +1057,7 @@ class VIEW3D_PT_tools_weightpaint(View3DPanel, bpy.types.Panel): col.operator("object.vertex_group_levels", text="Levels") -class VIEW3D_PT_tools_weightpaint_options(View3DPanel, bpy.types.Panel): +class VIEW3D_PT_tools_weightpaint_options(View3DPanel, Panel): bl_context = "weightpaint" bl_label = "Options" @@ -1093,7 +1094,7 @@ class VIEW3D_PT_tools_weightpaint_options(View3DPanel, bpy.types.Panel): # ********** default tools for vertexpaint **************** -class VIEW3D_PT_tools_vertexpaint(View3DPanel, bpy.types.Panel): +class VIEW3D_PT_tools_vertexpaint(View3DPanel, Panel): bl_context = "vertexpaint" bl_label = "Options" @@ -1122,7 +1123,7 @@ class VIEW3D_PT_tools_vertexpaint(View3DPanel, bpy.types.Panel): # ********** default tools for texturepaint **************** -class VIEW3D_PT_tools_projectpaint(View3DPanel, bpy.types.Panel): +class VIEW3D_PT_tools_projectpaint(View3DPanel, Panel): bl_context = "imagepaint" bl_label = "Project Paint" @@ -1214,7 +1215,7 @@ class VIEW3D_PT_imagepaint_options(PaintPanel): col.prop(tool_settings, "sculpt_paint_use_unified_strength", text="Strength") -class VIEW3D_MT_tools_projectpaint_clone(bpy.types.Menu): +class VIEW3D_MT_tools_projectpaint_clone(Menu): bl_label = "Clone Layer" def draw(self, context): @@ -1225,7 +1226,7 @@ class VIEW3D_MT_tools_projectpaint_clone(bpy.types.Menu): prop.value = i -class VIEW3D_MT_tools_projectpaint_stencil(bpy.types.Menu): +class VIEW3D_MT_tools_projectpaint_stencil(Menu): bl_label = "Mask Layer" def draw(self, context): @@ -1236,7 +1237,7 @@ class VIEW3D_MT_tools_projectpaint_stencil(bpy.types.Menu): prop.value = i -class VIEW3D_PT_tools_particlemode(View3DPanel, bpy.types.Panel): +class VIEW3D_PT_tools_particlemode(View3DPanel, Panel): '''default tools for particle mode''' bl_context = "particlemode" bl_label = "Options" -- cgit v1.2.3 From 24b18fd154d17373525a12e0f9a58c78143262ee Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Fri, 12 Aug 2011 18:10:31 +0000 Subject: More work on Advanced Retargeting and some stride bone bugs --- release/scripts/modules/retarget.py | 62 +++++++++++++++++++++++++------------ release/scripts/startup/ui_mocap.py | 6 +++- 2 files changed, 47 insertions(+), 21 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 827d3d11ddc..d4deb159b22 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -277,20 +277,20 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame if "stride_bone" in bpy.data.objects: stride_action = bpy.data.actions.new("Stride Bone " + action_name) stride_action.use_fake_user = True - stride_bone = enduser_obj.parent + #~ stride_bone = enduser_obj.parent stride_bone.animation_data.action = stride_action else: bpy.ops.object.add() stride_bone = bpy.context.active_object stride_bone.name = "stride_bone" print(stride_bone) - stride_bone.location = Vector((0, 0, 0)) + stride_bone.location = enduser_obj_mat.to_translation() print(linearAvg) if linearAvg: #determine the average change in scale needed avg = sum(linearAvg) / len(linearAvg) scene.frame_set(s_frame) - initialPos = (tailLoc(perf_bones[perfRoot]) / avg) + stride_bone.location + initialPos = (tailLoc(perf_bones[perfRoot]) / avg) #+ stride_bone.location for t in range(s_frame, e_frame): scene.frame_set(t) #calculate the new position, by dividing by the found ratio between performer and enduser @@ -298,6 +298,7 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame stride_bone.location = enduser_obj_mat * (newTranslation - initialPos) stride_bone.keyframe_insert("location") else: + stride_bone.keyframe_insert("location") stride_bone.animation_data.action.name = ("Stride Bone " + action_name) @@ -371,7 +372,7 @@ def cleanAndStoreObjMat(performer_obj, enduser_obj): #restore the object matrixes after parenting the auto generated IK empties -def restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone): +def restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone, scene, s_frame): pose_bones = enduser_obj.pose.bones for pose_bone in pose_bones: if pose_bone.name + "Org" in bpy.data.objects: @@ -379,6 +380,8 @@ def restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, str empty.parent = stride_bone performer_obj.matrix_world = perf_obj_mat enduser_obj.parent = stride_bone + scene.frame_set(s_frame) + enduser_obj_mat = enduser_obj_mat.to_3x3().to_4x4() * Matrix.Translation(stride_bone.matrix_world.to_translation()) enduser_obj.matrix_world = enduser_obj_mat @@ -455,20 +458,23 @@ def preAdvancedRetargeting(performer_obj, enduser_obj): createDictionary(performer_obj.data, enduser_obj.data) bones = enduser_obj.pose.bones map_bones = [bone for bone in bones if bone.bone.reverseMap] + perf_root = performer_obj.pose.bones[0].name for bone in map_bones: perf_bone = bone.bone.reverseMap[0].name addLocalRot = False; - if bone.bone.use_connect or not bone.constraints: + if (not bone.bone.use_connect) and (perf_bone!=perf_root): locks = bone.lock_location - if not (locks[0] or locks[1] or locks[2]): - cons = bone.constraints.new('COPY_LOCATION') - cons.name = "retargetTemp" - cons.use_x = not locks[0] - cons.use_y = not locks[1] - cons.use_z = not locks[2] - cons.target = performer_obj - cons.subtarget = perf_bone - addLocalRot = True + #if not (locks[0] or locks[1] or locks[2]): + cons = bone.constraints.new('COPY_LOCATION') + cons.name = "retargetTemp" + cons.use_x = not locks[0] + cons.use_y = not locks[1] + cons.use_z = not locks[2] + cons.target = performer_obj + cons.subtarget = perf_bone + cons.target_space = 'LOCAL' + cons.owner_space = 'LOCAL' + addLocalRot = True cons2 = bone.constraints.new('COPY_ROTATION') @@ -479,12 +485,17 @@ def preAdvancedRetargeting(performer_obj, enduser_obj): cons2.use_z = not locks[2] cons2.target = performer_obj cons2.subtarget = perf_bone + cons2.target_space = 'WORLD' + cons2.owner_space = 'WORLD' + + if perf_bone==perf_root: + addLocalRot = True - if addLocalRot: - for constraint in bone.constraints: - if constraint.type == 'COPY_ROTATION': - constraint.target_space = 'LOCAL' - constraint.owner_space = 'LOCAL_WITH_PARENT' + #~ if addLocalRot: + #~ for constraint in bone.constraints: + #~ if constraint.type == 'COPY_ROTATION': + #~ constraint.target_space = 'LOCAL' + #~ constraint.owner_space = 'LOCAL' def prepareForBake(enduser_obj): @@ -539,7 +550,7 @@ def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): if not advanced: IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene) bpy.ops.object.select_name(name=stride_bone.name, extend=False) - restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone) + restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone, scene, s_frame) bpy.ops.object.mode_set(mode='OBJECT') if not advanced: bpy.ops.object.select_name(name=inter_obj.name, extend=False) @@ -572,5 +583,16 @@ def profileWrapper(): e_frame = int(e_frame) totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame) + +def isRigAdvanced(enduser_obj): + bones = enduser_obj.pose.bones + for bone in bones: + for constraint in bone.constraints: + if constraint.type != "IK": + return True + if enduser_obj.data.animation_data: + if enduser_obj.data.animation_data.drivers: + return True + if __name__ == "__main__": cProfile.run("profileWrapper()") diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 19a96750e49..82f76d66d1b 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -404,7 +404,11 @@ class OBJECT_OT_RetargetButton(bpy.types.Operator): s_frame, e_frame = performer_obj.animation_data.action.frame_range s_frame = int(s_frame) e_frame = int(e_frame) - retarget.totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame) + if retarget.isRigAdvanced(enduser_obj) and not enduser_obj.data.advancedRetarget: + print("Recommended to use Advanced Retargeting method") + enduser_obj.data.advancedRetarget = True + else: + retarget.totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame) return {"FINISHED"} @classmethod -- cgit v1.2.3 From c5ef9b62c1f7f407c42bb48fe3362fa6cf3cf101 Mon Sep 17 00:00:00 2001 From: Mitchell Stokes Date: Fri, 12 Aug 2011 20:53:29 +0000 Subject: BGE Animations: Adding an option to let users choose whether or not to lock animation updates to the framerate. If this option is enabled, animations are only updated at the same speed as the animation framerate. This can give a significant speed up in performance, but at the cost of smoothness in animations. I'm defaulting this behavior to off for now, which is the behavior seen in trunk. --- release/scripts/startup/bl_ui/properties_game.py | 1 + 1 file changed, 1 insertion(+) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py index 58b2cacfbcc..dc397635452 100644 --- a/release/scripts/startup/bl_ui/properties_game.py +++ b/release/scripts/startup/bl_ui/properties_game.py @@ -342,6 +342,7 @@ class RENDER_PT_game_performance(RenderButtonsPanel, bpy.types.Panel): row = layout.row() row.prop(gs, "use_frame_rate") row.prop(gs, "use_display_lists") + row.prop(gs, "restrict_animation_updates") class RENDER_PT_game_display(RenderButtonsPanel, bpy.types.Panel): -- cgit v1.2.3 From aaeb498c26bf1241ab6f0b50976afdecd7636288 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Sat, 13 Aug 2011 11:09:42 +0000 Subject: Added a small operator to ease mapping. When used, the hierarchy mapping field is filled with the currently selected (pose) bone. --- release/scripts/startup/ui_mocap.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'release') diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 82f76d66d1b..0820b6183f4 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -283,6 +283,7 @@ class MocapPanel(bpy.types.Panel): row.prop(data=bone, property='foot', text='', icon='POSE_DATA') row.label(bone.name) row.prop_search(bone, "map", enduser_arm, "bones") + row.operator("mocap.selectmap", text='', icon='CURSOR').perf_bone = bone.name label_mod = "FK" if bone.map: pose_bone = perf_pose_bones[bone.map] @@ -493,6 +494,37 @@ class OBJECT_OT_LoadMappingButton(bpy.types.Operator): return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) else: return False + + +class OBJECT_OT_SelectMapBoneButton(bpy.types.Operator): + '''Select a bone for faster mapping''' + bl_idname = "mocap.selectmap" + bl_label = "Select a bone for faster mapping" + perf_bone = bpy.props.StringProperty() + + def execute(self, context): + enduser_obj = bpy.context.active_object + performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj][0] + selectedBone = "" + for bone in enduser_obj.data.bones: + boneVis = bone.layers + for i in range(32): + if boneVis[i] and enduser_obj.data.layers[i]: + if bone.select: + selectedBone = bone.name + break + performer_obj.data.bones[self.perf_bone].map = selectedBone + return {"FINISHED"} + + @classmethod + def poll(cls, context): + if context.active_object: + activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) + performer_obj = [obj for obj in context.selected_objects if obj != context.active_object] + if performer_obj: + return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) + else: + return False class OBJECT_OT_ConvertSamplesButton(bpy.types.Operator): -- cgit v1.2.3 From 65d9d2e3e0edec49ea7befc0200542b59c956a33 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Sat, 13 Aug 2011 17:52:13 +0000 Subject: 2.6 UI Files: * Code cleanup in the space_*.py files. * Removed layout.column() statement in _MT_ panels, they are useless. * Only define variables at the beginning of a function! --- release/scripts/startup/bl_ui/space_console.py | 13 ++--- release/scripts/startup/bl_ui/space_dopesheet.py | 25 +++------ release/scripts/startup/bl_ui/space_graph.py | 19 ++----- release/scripts/startup/bl_ui/space_image.py | 65 ++++++++++++------------ release/scripts/startup/bl_ui/space_info.py | 6 ++- release/scripts/startup/bl_ui/space_logic.py | 12 ++--- release/scripts/startup/bl_ui/space_nla.py | 19 ++----- release/scripts/startup/bl_ui/space_node.py | 30 +++++------ release/scripts/startup/bl_ui/space_outliner.py | 29 +++++------ release/scripts/startup/bl_ui/space_sequencer.py | 18 ++----- release/scripts/startup/bl_ui/space_text.py | 6 --- release/scripts/startup/bl_ui/space_time.py | 7 ++- 12 files changed, 94 insertions(+), 155 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_console.py b/release/scripts/startup/bl_ui/space_console.py index 5064f0744af..d457a66def8 100644 --- a/release/scripts/startup/bl_ui/space_console.py +++ b/release/scripts/startup/bl_ui/space_console.py @@ -26,17 +26,14 @@ class CONSOLE_HT_header(Header): bl_space_type = 'CONSOLE' def draw(self, context): - layout = self.layout + layout = self.layout.row(align=True) - row = layout.row(align=True) - row.template_header() + layout.template_header() if context.area.show_menus: - sub = row.row(align=True) - sub.menu("CONSOLE_MT_console") + layout.menu("CONSOLE_MT_console") - row = layout.row(align=True) - row.operator("console.autocomplete", text="Autocomplete") + layout.operator("console.autocomplete", text="Autocomplete") class CONSOLE_MT_console(Menu): @@ -44,7 +41,7 @@ class CONSOLE_MT_console(Menu): def draw(self, context): layout = self.layout - layout.column() + layout.operator("console.clear") layout.operator("console.copy") layout.operator("console.paste") diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 73624b490bf..dfbd7b3ae14 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -97,21 +97,19 @@ class DOPESHEET_HT_header(Header): row.template_header() if context.area.show_menus: - sub = row.row(align=True) - - sub.menu("DOPESHEET_MT_view") - sub.menu("DOPESHEET_MT_select") - sub.menu("DOPESHEET_MT_marker") + row.menu("DOPESHEET_MT_view") + row.menu("DOPESHEET_MT_select") + row.menu("DOPESHEET_MT_marker") if st.mode == 'DOPESHEET' or (st.mode == 'ACTION' and st.action != None): - sub.menu("DOPESHEET_MT_channel") + row.menu("DOPESHEET_MT_channel") elif st.mode == 'GPENCIL': - sub.menu("DOPESHEET_MT_gpencil_channel") + row.menu("DOPESHEET_MT_gpencil_channel") if st.mode != 'GPENCIL': - sub.menu("DOPESHEET_MT_key") + row.menu("DOPESHEET_MT_key") else: - sub.menu("DOPESHEET_MT_gpencil_frame") + row.menu("DOPESHEET_MT_gpencil_frame") layout.prop(st, "mode", text="") layout.prop(st.dopesheet, "show_summary", text="Summary") @@ -143,8 +141,6 @@ class DOPESHEET_MT_view(Menu): st = context.space_data - layout.column() - layout.prop(st, "use_realtime_update") layout.prop(st, "show_frame_indicator") layout.prop(st, "show_sliders") @@ -177,7 +173,6 @@ class DOPESHEET_MT_select(Menu): def draw(self, context): layout = self.layout - layout.column() # This is a bit misleading as the operator's default text is "Select All" while it actually *toggles* All/None layout.operator("action.select_all_toggle") layout.operator("action.select_all_toggle", text="Invert Selection").invert = True @@ -217,7 +212,6 @@ class DOPESHEET_MT_marker(Menu): #layout.operator_context = 'EXEC_REGION_WIN' - layout.column() layout.operator("marker.add", "Add Marker") layout.operator("marker.duplicate", text="Duplicate Marker") layout.operator("marker.delete", text="Delete Marker") @@ -246,7 +240,6 @@ class DOPESHEET_MT_channel(Menu): layout.operator_context = 'INVOKE_REGION_CHANNELS' - layout.column() layout.operator("anim.channels_delete") layout.separator() @@ -275,7 +268,6 @@ class DOPESHEET_MT_key(Menu): def draw(self, context): layout = self.layout - layout.column() layout.menu("DOPESHEET_MT_key_transform", text="Transform") layout.operator_menu_enum("action.snap", "type", text="Snap") @@ -308,7 +300,6 @@ class DOPESHEET_MT_key_transform(Menu): def draw(self, context): layout = self.layout - layout.column() layout.operator("transform.transform", text="Grab/Move").mode = 'TIME_TRANSLATE' layout.operator("transform.transform", text="Extend").mode = 'TIME_EXTEND' layout.operator("transform.transform", text="Slide").mode = 'TIME_SLIDE' @@ -326,7 +317,6 @@ class DOPESHEET_MT_gpencil_channel(Menu): layout.operator_context = 'INVOKE_REGION_CHANNELS' - layout.column() layout.operator("anim.channels_delete") layout.separator() @@ -352,7 +342,6 @@ class DOPESHEET_MT_gpencil_frame(Menu): def draw(self, context): layout = self.layout - layout.column() layout.menu("DOPESHEET_MT_key_transform", text="Transform") #layout.operator_menu_enum("action.snap", "type", text="Snap") diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index f6ba6ed7942..c379ea95ea2 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -36,13 +36,11 @@ class GRAPH_HT_header(Header): row.template_header() if context.area.show_menus: - sub = row.row(align=True) - - sub.menu("GRAPH_MT_view") - sub.menu("GRAPH_MT_select") - sub.menu("GRAPH_MT_marker") - sub.menu("GRAPH_MT_channel") - sub.menu("GRAPH_MT_key") + row.menu("GRAPH_MT_view") + row.menu("GRAPH_MT_select") + row.menu("GRAPH_MT_marker") + row.menu("GRAPH_MT_channel") + row.menu("GRAPH_MT_key") layout.prop(st, "mode", text="") @@ -70,8 +68,6 @@ class GRAPH_MT_view(Menu): st = context.space_data - layout.column() - layout.operator("graph.properties", icon='MENU_PANEL') layout.separator() @@ -114,7 +110,6 @@ class GRAPH_MT_select(Menu): def draw(self, context): layout = self.layout - layout.column() # This is a bit misleading as the operator's default text is "Select All" while it actually *toggles* All/None layout.operator("graph.select_all_toggle") layout.operator("graph.select_all_toggle", text="Invert Selection").invert = True @@ -151,7 +146,6 @@ class GRAPH_MT_marker(Menu): #layout.operator_context = 'EXEC_REGION_WIN' - layout.column() layout.operator("marker.add", "Add Marker") layout.operator("marker.duplicate", text="Duplicate Marker") layout.operator("marker.delete", text="Delete Marker") @@ -172,7 +166,6 @@ class GRAPH_MT_channel(Menu): layout.operator_context = 'INVOKE_REGION_CHANNELS' - layout.column() layout.operator("anim.channels_delete") layout.separator() @@ -202,7 +195,6 @@ class GRAPH_MT_key(Menu): def draw(self, context): layout = self.layout - layout.column() layout.menu("GRAPH_MT_key_transform", text="Transform") layout.operator_menu_enum("graph.snap", "type", text="Snap") @@ -241,7 +233,6 @@ class GRAPH_MT_key_transform(Menu): def draw(self, context): layout = self.layout - layout.column() layout.operator("transform.translate", text="Grab/Move") layout.operator("transform.transform", text="Extend").mode = 'TIME_EXTEND' layout.operator("transform.rotate", text="Rotate") diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index 0278863ca27..5d72482ce9c 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -452,15 +452,13 @@ class IMAGE_PT_game_properties(Panel): split = layout.split() col = split.column() - + + col.prop(ima, "use_animation") sub = col.column(align=True) - sub.prop(ima, "use_animation") - - subsub = sub.column() - subsub.active = ima.use_animation - subsub.prop(ima, "frame_start", text="Start") - subsub.prop(ima, "frame_end", text="End") - subsub.prop(ima, "fps", text="Speed") + sub.active = ima.use_animation + sub.prop(ima, "frame_start", text="Start") + sub.prop(ima, "frame_end", text="End") + sub.prop(ima, "fps", text="Speed") col.prop(ima, "use_tiles") sub = col.column(align=True) @@ -509,10 +507,11 @@ class IMAGE_PT_view_waveform(Panel): layout = self.layout sima = context.space_data + layout.template_waveform(sima, "scopes") - sub = layout.row().split(percentage=0.75) - sub.prop(sima.scopes, "waveform_alpha") - sub.prop(sima.scopes, "waveform_mode", text="", icon_only=True) + row = layout.split(percentage=0.75) + row.prop(sima.scopes, "waveform_alpha") + row.prop(sima.scopes, "waveform_mode", text="", icon_only=True) class IMAGE_PT_view_vectorscope(Panel): @@ -545,8 +544,10 @@ class IMAGE_PT_sample_line(Panel): def draw(self, context): layout = self.layout - layout.operator("image.sample_line") + sima = context.space_data + + layout.operator("image.sample_line") layout.template_histogram(sima, "sample_histogram") layout.prop(sima.sample_histogram, "mode") @@ -563,13 +564,14 @@ class IMAGE_PT_scope_sample(Panel): def draw(self, context): layout = self.layout + sima = context.space_data - split = layout.split() - row = split.row() + + row = layout.row() row.prop(sima.scopes, "use_full_resolution") - row = split.row() - row.active = not sima.scopes.use_full_resolution - row.prop(sima.scopes, "accuracy") + sub = row.row() + sub.active = not sima.scopes.use_full_resolution + sub.prop(sima.scopes, "accuracy") class IMAGE_PT_view_properties(Panel): @@ -609,16 +611,16 @@ class IMAGE_PT_view_properties(Panel): if show_uvedit: col = layout.column() - col.label("Cursor Location") - row = col.row() - row.prop(uvedit, "cursor_location", text="") - - col = layout.column() + col.label("Cursor Location:") + col.row().prop(uvedit, "cursor_location", text="") + + col.separator() + col.label(text="UVs:") - row = col.row() - row.prop(uvedit, "edge_draw_type", expand=True) + col.row().prop(uvedit, "edge_draw_type", expand=True) split = layout.split() + col = split.column() col.prop(uvedit, "show_faces") col.prop(uvedit, "show_smooth_edges", text="Smooth") @@ -647,9 +649,8 @@ class IMAGE_PT_paint(Panel): toolsettings = context.tool_settings.image_paint brush = toolsettings.brush - col = layout.split().column() - row = col.row() - col.template_ID_preview(toolsettings, "brush", new="brush.add", rows=3, cols=8) + col = layout.column() + col.template_ID_preview(toolsettings, "brush", new="brush.add", rows=2, cols=6) if brush: col = layout.column() @@ -700,9 +701,7 @@ class IMAGE_PT_tools_brush_tool(BrushButtonsPanel, Panel): settings = context.tool_settings.image_paint brush = settings.brush - col = layout.column(align=True) - - col.prop(brush, "image_tool", expand=False, text="") + layout.prop(brush, "image_tool", text="") row = layout.row(align=True) row.prop(brush, "use_paint_sculpt", text="", icon='SCULPTMODE_HLT') @@ -722,9 +721,9 @@ class IMAGE_PT_paint_stroke(BrushButtonsPanel, Panel): brush = toolsettings.brush layout.prop(brush, "use_airbrush") - col = layout.column() - col.active = brush.use_airbrush - col.prop(brush, "rate", slider=True) + row = layout.row() + row.active = brush.use_airbrush + row.prop(brush, "rate", slider=True) layout.prop(brush, "use_space") row = layout.row(align=True) diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index 12873743a23..38c1e24f27e 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -92,7 +92,7 @@ class INFO_MT_report(Menu): def draw(self, context): layout = self.layout - layout.column() + layout.operator("console.select_all_toggle") layout.operator("console.select_border") layout.operator("console.report_delete") @@ -194,6 +194,7 @@ class INFO_MT_mesh_add(Menu): def draw(self, context): layout = self.layout + layout.operator_context = 'INVOKE_REGION_WIN' layout.operator("mesh.primitive_plane_add", icon='MESH_PLANE', text="Plane") layout.operator("mesh.primitive_cube_add", icon='MESH_CUBE', text="Cube") @@ -214,6 +215,7 @@ class INFO_MT_curve_add(Menu): def draw(self, context): layout = self.layout + layout.operator_context = 'INVOKE_REGION_WIN' layout.operator("curve.primitive_bezier_curve_add", icon='CURVE_BEZCURVE', text="Bezier") layout.operator("curve.primitive_bezier_circle_add", icon='CURVE_BEZCIRCLE', text="Circle") @@ -244,6 +246,7 @@ class INFO_MT_surface_add(Menu): def draw(self, context): layout = self.layout + layout.operator_context = 'INVOKE_REGION_WIN' layout.operator("surface.primitive_nurbs_surface_curve_add", icon='SURFACE_NCURVE', text="NURBS Curve") layout.operator("surface.primitive_nurbs_surface_circle_add", icon='SURFACE_NCIRCLE', text="NURBS Circle") @@ -259,6 +262,7 @@ class INFO_MT_armature_add(Menu): def draw(self, context): layout = self.layout + layout.operator_context = 'INVOKE_REGION_WIN' layout.operator("object.armature_add", text="Single Bone", icon='BONE_DATA') diff --git a/release/scripts/startup/bl_ui/space_logic.py b/release/scripts/startup/bl_ui/space_logic.py index 1b774539d0f..869a91124d3 100644 --- a/release/scripts/startup/bl_ui/space_logic.py +++ b/release/scripts/startup/bl_ui/space_logic.py @@ -65,16 +65,12 @@ class LOGIC_HT_header(Header): bl_space_type = 'LOGIC_EDITOR' def draw(self, context): - layout = self.layout + layout = self.layout.row(align=True) - row = layout.row(align=True) - row.template_header() + layout.template_header() if context.area.show_menus: - sub = row.row(align=True) - sub.menu("LOGIC_MT_view") - #sub.menu("LOGIC_MT_select") - #sub.menu("LOGIC_MT_add") + layout.menu("LOGIC_MT_view") class LOGIC_MT_view(Menu): @@ -83,8 +79,6 @@ class LOGIC_MT_view(Menu): def draw(self, context): layout = self.layout - layout.column() - layout.operator("logic.properties", icon='MENU_PANEL') if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py index 55f2dabba74..c69af2c9a60 100644 --- a/release/scripts/startup/bl_ui/space_nla.py +++ b/release/scripts/startup/bl_ui/space_nla.py @@ -36,13 +36,11 @@ class NLA_HT_header(Header): row.template_header() if context.area.show_menus: - sub = row.row(align=True) - - sub.menu("NLA_MT_view") - sub.menu("NLA_MT_select") - sub.menu("NLA_MT_marker") - sub.menu("NLA_MT_edit") - sub.menu("NLA_MT_add") + row.menu("NLA_MT_view") + row.menu("NLA_MT_select") + row.menu("NLA_MT_marker") + row.menu("NLA_MT_edit") + row.menu("NLA_MT_add") dopesheet_filter(layout, context) @@ -57,8 +55,6 @@ class NLA_MT_view(Menu): st = context.space_data - layout.column() - layout.operator("nla.properties", icon='MENU_PANEL') layout.separator() @@ -85,7 +81,6 @@ class NLA_MT_select(Menu): def draw(self, context): layout = self.layout - layout.column() # This is a bit misleading as the operator's default text is "Select All" while it actually *toggles* All/None layout.operator("nla.select_all_toggle") layout.operator("nla.select_all_toggle", text="Invert Selection").invert = True @@ -107,7 +102,6 @@ class NLA_MT_marker(Menu): #layout.operator_context = 'EXEC_REGION_WIN' - layout.column() layout.operator("marker.add", "Add Marker") layout.operator("marker.duplicate", text="Duplicate Marker") layout.operator("marker.delete", text="Delete Marker") @@ -126,7 +120,6 @@ class NLA_MT_edit(Menu): scene = context.scene - layout.column() layout.menu("NLA_MT_edit_transform", text="Transform") layout.operator_menu_enum("nla.snap", "type", text="Snap") @@ -167,7 +160,6 @@ class NLA_MT_add(Menu): def draw(self, context): layout = self.layout - layout.column() layout.operator("nla.actionclip_add") layout.operator("nla.transition_add") @@ -186,7 +178,6 @@ class NLA_MT_edit_transform(Menu): def draw(self, context): layout = self.layout - layout.column() layout.operator("transform.translate", text="Grab/Move") layout.operator("transform.transform", text="Extend").mode = 'TIME_EXTEND' layout.operator("transform.transform", text="Scale").mode = 'TIME_SCALE' diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py index b0a54004765..708017ba749 100644 --- a/release/scripts/startup/bl_ui/space_node.py +++ b/release/scripts/startup/bl_ui/space_node.py @@ -28,33 +28,29 @@ class NODE_HT_header(Header): layout = self.layout snode = context.space_data + snode_id = snode.id + id_from = snode.id_from row = layout.row(align=True) row.template_header() if context.area.show_menus: - sub = row.row(align=True) - sub.menu("NODE_MT_view") - sub.menu("NODE_MT_select") - sub.menu("NODE_MT_add") - sub.menu("NODE_MT_node") + row.menu("NODE_MT_view") + row.menu("NODE_MT_select") + row.menu("NODE_MT_add") + row.menu("NODE_MT_node") - row = layout.row() - row.prop(snode, "tree_type", text="", expand=True) + layout.prop(snode, "tree_type", text="", expand=True) if snode.tree_type == 'MATERIAL': - ob = snode.id_from - snode_id = snode.id - if ob: - layout.template_ID(ob, "active_material", new="material.new") + if id_from: + layout.template_ID(id_from, "active_material", new="material.new") if snode_id: layout.prop(snode_id, "use_nodes") elif snode.tree_type == 'TEXTURE': - row.prop(snode, "texture_type", text="", expand=True) + layout.prop(snode, "texture_type", text="", expand=True) - snode_id = snode.id - id_from = snode.id_from if id_from: if snode.texture_type == 'BRUSH': layout.template_ID(id_from, "texture", new="texture.new") @@ -64,10 +60,8 @@ class NODE_HT_header(Header): layout.prop(snode_id, "use_nodes") elif snode.tree_type == 'COMPOSITING': - scene = snode.id - - layout.prop(scene, "use_nodes") - layout.prop(scene.render, "use_free_unused_nodes", text="Free Unused") + layout.prop(snode_id, "use_nodes") + layout.prop(snode_id.render, "use_free_unused_nodes", text="Free Unused") layout.prop(snode, "show_backdrop") if snode.show_backdrop: row = layout.row(align=True) diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 004a913a463..b1e6eaf3245 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -72,14 +72,13 @@ class OUTLINER_MT_view(Menu): space = context.space_data - col = layout.column() if space.display_mode not in {'DATABLOCKS', 'USER_PREFERENCES', 'KEYMAPS'}: - col.prop(space, "show_restrict_columns") - col.separator() - col.operator("outliner.show_active") + layout.prop(space, "show_restrict_columns") + layout.separator() + layout.operator("outliner.show_active") - col.operator("outliner.show_one_level") - col.operator("outliner.show_hierarchy") + layout.operator("outliner.show_one_level") + layout.operator("outliner.show_hierarchy") layout.separator() @@ -95,10 +94,8 @@ class OUTLINER_MT_search(Menu): space = context.space_data - col = layout.column() - - col.prop(space, "use_filter_case_sensitive") - col.prop(space, "use_filter_complete") + layout.prop(space, "use_filter_case_sensitive") + layout.prop(space, "use_filter_complete") class OUTLINER_MT_edit_datablocks(Menu): @@ -107,15 +104,13 @@ class OUTLINER_MT_edit_datablocks(Menu): def draw(self, context): layout = self.layout - col = layout.column() - - col.operator("outliner.keyingset_add_selected") - col.operator("outliner.keyingset_remove_selected") + layout.operator("outliner.keyingset_add_selected") + layout.operator("outliner.keyingset_remove_selected") - col.separator() + layout.separator() - col.operator("outliner.drivers_add_selected") - col.operator("outliner.drivers_delete_selected") + layout.operator("outliner.drivers_add_selected") + layout.operator("outliner.drivers_delete_selected") if __name__ == "__main__": # only for live edit. bpy.utils.register_module(__name__) diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index f58bd7c9150..23dfdcfba90 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -40,14 +40,13 @@ class SEQUENCER_HT_header(Header): row.template_header() if context.area.show_menus: - sub = row.row(align=True) - sub.menu("SEQUENCER_MT_view") + row.menu("SEQUENCER_MT_view") if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}: - sub.menu("SEQUENCER_MT_select") - sub.menu("SEQUENCER_MT_marker") - sub.menu("SEQUENCER_MT_add") - sub.menu("SEQUENCER_MT_strip") + row.menu("SEQUENCER_MT_select") + row.menu("SEQUENCER_MT_marker") + row.menu("SEQUENCER_MT_add") + row.menu("SEQUENCER_MT_strip") layout.prop(st, "view_type", expand=True, text="") @@ -96,8 +95,6 @@ class SEQUENCER_MT_view(Menu): st = context.space_data - layout.column() - layout.operator("sequencer.properties", icon='MENU_PANEL') layout.separator() @@ -136,7 +133,6 @@ class SEQUENCER_MT_select(Menu): def draw(self, context): layout = self.layout - layout.column() layout.operator("sequencer.select_active_side", text="Strips to the Left").side = 'LEFT' layout.operator("sequencer.select_active_side", text="Strips to the Right").side = 'RIGHT' layout.separator() @@ -157,7 +153,6 @@ class SEQUENCER_MT_marker(Menu): #layout.operator_context = 'EXEC_REGION_WIN' - layout.column() layout.operator("marker.add", "Add Marker") layout.operator("marker.duplicate", text="Duplicate Marker") layout.operator("marker.delete", text="Delete Marker") @@ -190,7 +185,6 @@ class SEQUENCER_MT_add(Menu): layout = self.layout layout.operator_context = 'INVOKE_REGION_WIN' - layout.column() if len(bpy.data.scenes) > 10: layout.operator_context = 'INVOKE_DEFAULT' layout.operator("sequencer.scene_strip_add", text="Scene...") @@ -211,7 +205,6 @@ class SEQUENCER_MT_add_effect(Menu): layout = self.layout layout.operator_context = 'INVOKE_REGION_WIN' - layout.column() layout.operator("sequencer.effect_strip_add", text="Add").type = 'ADD' layout.operator("sequencer.effect_strip_add", text="Subtract").type = 'SUBTRACT' layout.operator("sequencer.effect_strip_add", text="Alpha Over").type = 'ALPHA_OVER' @@ -238,7 +231,6 @@ class SEQUENCER_MT_strip(Menu): layout.operator_context = 'INVOKE_REGION_WIN' - layout.column() layout.operator("transform.transform", text="Grab/Move").mode = 'TRANSLATION' layout.operator("transform.transform", text="Grab/Extend from frame").mode = 'TIME_EXTEND' # uiItemO(layout, NULL, 0, "sequencer.strip_snap"); // TODO - add this operator diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py index f3b8b9ce221..300211a26bf 100644 --- a/release/scripts/startup/bl_ui/space_text.py +++ b/release/scripts/startup/bl_ui/space_text.py @@ -172,7 +172,6 @@ class TEXT_MT_text(Menu): st = context.space_data text = st.text - layout.column() layout.operator("text.new") layout.operator("text.open") @@ -189,11 +188,6 @@ class TEXT_MT_text(Menu): layout.column() layout.operator("text.run_script") - #ifdef WITH_PYTHON - # XXX if(BPY_is_pyconstraint(text)) - # XXX uiMenuItemO(head, 0, "text.refresh_pyconstraints"); - #endif - class TEXT_MT_templates(Menu): bl_label = "Templates" diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py index 0b5aec7d5f2..db009fe43c2 100644 --- a/release/scripts/startup/bl_ui/space_time.py +++ b/release/scripts/startup/bl_ui/space_time.py @@ -35,10 +35,9 @@ class TIME_HT_header(Header): row.template_header() if context.area.show_menus: - sub = row.row(align=True) - sub.menu("TIME_MT_view") - sub.menu("TIME_MT_frame") - sub.menu("TIME_MT_playback") + row.menu("TIME_MT_view") + row.menu("TIME_MT_frame") + row.menu("TIME_MT_playback") layout.prop(scene, "use_preview_range", text="", toggle=True) -- cgit v1.2.3 From 2fef8f13f0189a8a748e6729081a4e5cb769314b Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Sat, 13 Aug 2011 18:46:34 +0000 Subject: Added argument to retargeting - step size. Allows retargeting every other 'step' frame, useful for previewing or faster retargeting. --- release/scripts/modules/retarget.py | 28 ++++++++++++++++------------ release/scripts/startup/ui_mocap.py | 5 +++++ 2 files changed, 21 insertions(+), 12 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index d4deb159b22..de02913f5a7 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -69,7 +69,7 @@ def loadMapping(perf_arm, end_arm): # easily while concentrating on the hierarchy changes -def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene): +def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene, step): #creates and keyframes an empty with its location #the original position of the tail bone #useful for storing the important data in the original motion @@ -80,7 +80,10 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene perf_world_rotation = perf_bone.matrix * performer_obj.matrix_world inter_world_base_rotation = inter_bone.bone.matrix_local * inter_obj.matrix_world inter_world_base_inv = inter_world_base_rotation.inverted() - return (inter_world_base_inv.to_3x3() * perf_world_rotation.to_3x3()).to_4x4() + bake_matrix = (inter_world_base_inv.to_3x3() * perf_world_rotation.to_3x3()) + base_euler = inter_bone.rotation_euler + eul = bake_matrix.to_euler(base_euler.order,base_euler) + return eul.to_matrix().to_4x4() #uses 1to1 and interpolation/averaging to match many to 1 retarget def manyPerfToSingleInterRetarget(inter_bone, performer_bones_s): @@ -142,7 +145,7 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene else: inter_bone.bone.use_inherit_rotation = True - for t in range(s_frame, e_frame): + for t in range(s_frame, e_frame, step): if (t - s_frame) % 10 == 0: print("First pass: retargeting frame {0}/{1}".format(t, e_frame - s_frame)) scene.frame_set(t) @@ -161,7 +164,7 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene # Scale: ? Should work but needs testing. -def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene): +def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene, step): inter_bones = inter_obj.pose.bones end_bones = enduser_obj.pose.bones @@ -198,7 +201,7 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene): for bone in end_bone.children: bakeTransform(bone) - for t in range(s_frame, e_frame): + for t in range(s_frame, e_frame, step): if (t - s_frame) % 10 == 0: print("Second pass: retargeting frame {0}/{1}".format(t, e_frame - s_frame)) scene.frame_set(t) @@ -277,7 +280,7 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame if "stride_bone" in bpy.data.objects: stride_action = bpy.data.actions.new("Stride Bone " + action_name) stride_action.use_fake_user = True - #~ stride_bone = enduser_obj.parent + stride_bone = enduser_obj.parent stride_bone.animation_data.action = stride_action else: bpy.ops.object.add() @@ -305,7 +308,7 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame return stride_bone -def IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene): +def IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene, step): bpy.ops.object.select_name(name=enduser_obj.name, extend=False) end_bones = enduser_obj.pose.bones for pose_bone in end_bones: @@ -332,7 +335,7 @@ def IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene): target = ik_constraint.target # bake the correct locations for the ik target bones - for t in range(s_frame, e_frame): + for t in range(s_frame, e_frame, step): scene.frame_set(t) if target_is_bone: final_loc = pose_bone.tail - target.bone.matrix_local.to_translation() @@ -522,6 +525,7 @@ def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): perf_arm = performer_obj.data end_arm = enduser_obj.data advanced = end_arm.advancedRetarget + step = end_arm.frameStep try: enduser_obj.animation_data.action = bpy.data.actions.new("temp") @@ -536,19 +540,19 @@ def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): if not advanced: turnOffIK(enduser_obj) print("Creating intermediate armature (for first pass)") - inter_obj = createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene) + inter_obj = createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene, step) print("First pass: retargeting from intermediate to end user") - retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene) + retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene, step) else: prepareForBake(enduser_obj) print("Retargeting pose (Advanced Retarget)") - nla.bake(s_frame, e_frame, action=enduser_obj.animation_data.action, only_selected=True, do_pose=True, do_object=False) + nla.bake(s_frame, e_frame, action=enduser_obj.animation_data.action, only_selected=True, do_pose=True, do_object=False, step=step) name = performer_obj.animation_data.action.name enduser_obj.animation_data.action.name = "Base " + name print("Second pass: retargeting root translation and clean up") stride_bone = copyTranslation(performer_obj, enduser_obj, feetBones, root, s_frame, e_frame, scene, enduser_obj_mat) if not advanced: - IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene) + IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene, step) bpy.ops.object.select_name(name=stride_bone.name, extend=False) restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone, scene, s_frame) bpy.ops.object.mode_set(mode='OBJECT') diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 0820b6183f4..9be26a3b2ff 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -161,6 +161,10 @@ bpy.types.Armature.stitch_settings = bpy.props.PointerProperty(type=AnimationSti bpy.types.Armature.active_mocap = bpy.props.StringProperty(update=retarget.NLASystemInitialize) bpy.types.Armature.mocapNLATracks = bpy.props.CollectionProperty(type=MocapNLATracks) bpy.types.Armature.advancedRetarget = bpy.props.BoolProperty(default=False, update=advancedRetargetToggle) +bpy.types.Armature.frameStep = smooth_out = bpy.props.IntProperty(name="Frame Skip", + default=1, + description="Amount of frames to skip - for previewing retargets quickly. 1 is fully sampled", + min=1) #Update function for IK functionality. Is called when IK prop checkboxes are toggled. @@ -301,6 +305,7 @@ class MocapPanel(bpy.types.Panel): mapRow.operator("mocap.loadmapping", text='Load mapping') self.layout.prop(data=performer_obj.animation_data.action, property='name', text='Action Name') self.layout.prop(enduser_arm, "advancedRetarget", text='Advanced Retarget') + self.layout.prop(enduser_arm, "frameStep") self.layout.operator("mocap.retarget", text='RETARGET!') -- cgit v1.2.3 From fc128c970b0e6617cbc67d504d3f4f07c4ae45fd Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 14 Aug 2011 03:59:22 +0000 Subject: - recently restored sequencer change data operator didnt reset the offsets after a hard cut, causing the new data to be trimmed. - add change data operator to strip panel next to image file properties since editing every image manually isnt really usable. - added new sequencer operator "Clear Offsets" (Alt+O), useful to reset the start/end frames around the strip data. --- release/scripts/startup/bl_ui/space_sequencer.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 23dfdcfba90..84cc365425e 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -239,6 +239,7 @@ class SEQUENCER_MT_strip(Menu): layout.operator("sequencer.cut", text="Cut (hard) at frame").type = 'HARD' layout.operator("sequencer.cut", text="Cut (soft) at frame").type = 'SOFT' layout.operator("sequencer.images_separate") + layout.operator("sequencer.offset_clear") layout.operator("sequencer.deinterlace_selected_movies") layout.separator() @@ -381,6 +382,8 @@ class SEQUENCER_PT_edit(SequencerButtonsPanel, Panel): if elem and elem.orig_width > 0 and elem.orig_height > 0: col.label(text="Orig Dim: %dx%d" % (elem.orig_width, elem.orig_height)) + else: + col.label(text="Orig Dim: None") class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): @@ -565,6 +568,9 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel): col = split.column() col.prop(elem, "filename", text="") # strip.elements[0] could be a fallback + # also accessible from the menu + layout.operator("sequencer.change_path") + elif seq_type == 'MOVIE': split = layout.split(percentage=0.2) col = split.column() -- cgit v1.2.3 From 0b23d378fbac8e76d4885c3485a4dbf158aab136 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 14 Aug 2011 06:43:58 +0000 Subject: fix [#28225] Solidify Modifier creates wrong results when vertex group is attached infact this is not really a bug, irrespective zero vertex group weights gave overlapping geometry which isn't useful, add an option to set the thickness factor for zero weighted verts. --- release/scripts/startup/bl_ui/properties_data_mesh.py | 2 +- release/scripts/startup/bl_ui/properties_data_modifier.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index 75df7dad5f2..896b76c59f6 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -73,7 +73,7 @@ class DATA_PT_context_mesh(MeshButtonsPanel, Panel): ob = context.object mesh = context.mesh space = context.space_data - + layout.prop(context.scene.tool_settings, "mesh_select_mode", index=0, text="Vertex") if ob: layout.template_ID(ob, "data") elif mesh: diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index e4bbd7d7d7d..179921c3c85 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -577,13 +577,13 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): sub = col.column() sub.active = bool(md.vertex_group) sub.prop(md, "invert_vertex_group", text="Invert") + sub.prop(md, "thickness_vertex_group", text="Factor") col.prop(md, "use_even_offset") col.prop(md, "use_quality_normals") col.prop(md, "use_rim") sub = col.column() - sub.label() row = sub.split(align=True, percentage=0.4) row.prop(md, "material_offset", text="") row = row.row() -- cgit v1.2.3 From 8490d646b7ac47fd5f0ed8c28cfc864f5286aa7a Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Sun, 14 Aug 2011 09:12:43 +0000 Subject: Fixing bug with editing keymaps when filter is enabled. --- release/scripts/startup/bl_ui/space_userpref_keymap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_userpref_keymap.py b/release/scripts/startup/bl_ui/space_userpref_keymap.py index d595b32c710..6a81ff5830e 100644 --- a/release/scripts/startup/bl_ui/space_userpref_keymap.py +++ b/release/scripts/startup/bl_ui/space_userpref_keymap.py @@ -18,7 +18,7 @@ # import bpy -from bpy.types import Menu, Operator +from bpy.types import Menu, Operator, OperatorProperties import os -- cgit v1.2.3 From 551e8bc72c1a0be6fbc32153952036e3fc83560f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 15 Aug 2011 04:58:19 +0000 Subject: py api - optional sep argument for bpy_extra.io_utils.unique_name() since for some formats '.' is an invalid char. --- release/scripts/modules/bpy_extras/io_utils.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py index bb4e95c051f..6271c1f77b5 100644 --- a/release/scripts/modules/bpy_extras/io_utils.py +++ b/release/scripts/modules/bpy_extras/io_utils.py @@ -439,7 +439,7 @@ def path_reference_copy(copy_set, report=print): shutil.copy(file_src, file_dst) -def unique_name(key, name, name_dict, name_max=-1, clean_func=None): +def unique_name(key, name, name_dict, name_max=-1, clean_func=None, sep="."): """ Helper function for storing unique names which may have special characters stripped and restricted to a maximum length. @@ -456,6 +456,9 @@ def unique_name(key, name, name_dict, name_max=-1, clean_func=None): :type name_dict: dict :arg clean_func: Function to call on *name* before creating a unique value. :type clean_func: function + :arg sep: Separator to use when between the name and a number when a + duplicate name is found. + :type sep: string """ name_new = name_dict.get(key) if name_new is None: @@ -466,14 +469,15 @@ def unique_name(key, name, name_dict, name_max=-1, clean_func=None): if name_max == -1: while name_new in name_dict_values: - name_new = "%s.%03d" % (name_new_orig, count) + name_new = "%s%s%03d" % (name_new_orig, sep, count) count += 1 else: name_new = name_new[:name_max] while name_new in name_dict_values: count_str = "%03d" % count - name_new = "%.*s.%s" % (name_max - (len(count_str) + 1), + name_new = "%.*s%s%s" % (name_max - (len(count_str) + 1), name_new_orig, + sep, count_str, ) count += 1 -- cgit v1.2.3 From 3237f39243ab431fbdf736e3b8648a0c19400564 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Mon, 15 Aug 2011 10:17:04 +0000 Subject: Small fix to autoloop due to changes in utility function by animation stitching --- release/scripts/modules/mocap_tools.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index f4b6a93f531..e5d4dcb6554 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -169,20 +169,24 @@ def crossCorrelationMatch(curvesA, curvesB, margin): def autoloop_anim(): context = bpy.context obj = context.active_object - fcurves = [x for x in obj.animation_data.action.fcurves if x.select] + + def locCurve(x): + x.data_path == "location" + + fcurves = [x for x in obj.animation_data.action.fcurves if not locCurve(x)] margin = 10 flm, s, data = crossCorrelationMatch(fcurves, fcurves, margin) - loop = data[s:s + flm + margin] + loop = data[s:s + flm] #find *all* loops, s:s+flm, s+flm:s+2flm, etc... #and interpolate between all # to find "the perfect loop". #Maybe before finding s? interp(i,i+flm,i+2flm).... - for i in range(1, margin + 1): - w1 = sqrt(float(i) / margin) - loop[-i] = (loop[-i] * w1) + (loop[0] * (1 - w1)) + #~ for i in range(1, margin + 1): + #~ w1 = sqrt(float(i) / margin) + #~ loop[-i] = (loop[-i] * w1) + (loop[0] * (1 - w1)) for curve in fcurves: pts = curve.keyframe_points @@ -192,9 +196,9 @@ def autoloop_anim(): for c, curve in enumerate(fcurves): pts = curve.keyframe_points for i in range(len(loop)): - pts.insert(i + 1, loop[i][c]) + pts.insert(i + 2, loop[i][c]) - context.scene.frame_end = flm + 1 + context.scene.frame_end = flm def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): -- cgit v1.2.3 From c8ae881b619ec2d2d05b3c55283ca1f4c69828ca Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Mon, 15 Aug 2011 10:18:02 +0000 Subject: Added option to each retargeted bone to fix twist issues caused by variable bone rolls and unknown axis differences. Also made retarget operator a single undo --- release/scripts/modules/retarget.py | 35 +++++++++++++++++++++++++++-------- release/scripts/startup/ui_mocap.py | 5 +++++ 2 files changed, 32 insertions(+), 8 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index de02913f5a7..2c4dcbe6bda 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -20,7 +20,7 @@ import bpy from mathutils import * -from math import radians, acos +from math import radians, acos, pi from bl_operators import nla import cProfile @@ -77,13 +77,21 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene #Simple 1to1 retarget of a bone def singleBoneRetarget(inter_bone, perf_bone): - perf_world_rotation = perf_bone.matrix * performer_obj.matrix_world - inter_world_base_rotation = inter_bone.bone.matrix_local * inter_obj.matrix_world + perf_world_rotation = perf_bone.matrix + inter_world_base_rotation = inter_bone.bone.matrix_local inter_world_base_inv = inter_world_base_rotation.inverted() bake_matrix = (inter_world_base_inv.to_3x3() * perf_world_rotation.to_3x3()) - base_euler = inter_bone.rotation_euler - eul = bake_matrix.to_euler(base_euler.order,base_euler) - return eul.to_matrix().to_4x4() + #~ orgEul = inter_bone.bone.matrix_local.to_euler("XYZ") + #~ eul = bake_matrix.to_euler("XYZ", orgEul) + #~ diff = -bake_matrix.to_euler().y + inter_bone.bone.matrix.to_euler().y + #~ eul.rotate_axis("Y", diff) + #~ eul.make_compatible(orgEul) + #~ bake_matrix = eul.to_matrix() + #~ #diff = abs(diff) + #bake_matrix = bake_matrix* Matrix.Rotation(pi/2, 3, "Y") + #~ scene = bpy.context.scene + #~ print(scene.frame_current, inter_bone.name, bake_matrix.to_euler().y) + return bake_matrix.to_4x4() #uses 1to1 and interpolation/averaging to match many to 1 retarget def manyPerfToSingleInterRetarget(inter_bone, performer_bones_s): @@ -109,7 +117,15 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene else: perf_bone = performer_bones[perf_bone_name[0].name] inter_bone.matrix_basis = singleBoneRetarget(inter_bone, perf_bone) - inter_bone.keyframe_insert("rotation_quaternion") + if inter_bone.bone.twistFix: + inter_bone.matrix_basis *= Matrix.Rotation(radians(180), 4, "Y") + rot_mode = inter_bone.rotation_mode + if rot_mode == "QUATERNION": + inter_bone.keyframe_insert("rotation_quaternion") + elif rot_mode == "AXIS_ANGLE": + inter_bone.keyframe_insert("rotation_axis_angle") + else: + inter_bone.keyframe_insert("rotation_euler") #creates the intermediate armature object inter_obj = enduser_obj.copy() @@ -119,6 +135,7 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene bpy.context.scene.objects.active = inter_obj bpy.ops.object.mode_set(mode='EDIT') #add some temporary connecting bones in case end user bones are not connected to their parents + rollDict = {} print("creating temp bones") for bone in inter_obj.data.edit_bones: if not bone.use_connect and bone.parent: @@ -130,9 +147,11 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene bone.parent = newBone bone.use_connect = True newBone.use_connect = True + rollDict[bone.name] = bone.roll + bone.roll = 0 #resets roll print("retargeting to intermediate") - bpy.ops.armature.calculate_roll(type='Z') + #bpy.ops.armature.calculate_roll(type='Z') bpy.ops.object.mode_set(mode="OBJECT") inter_obj.data.name = "inter_arm" inter_arm = inter_obj.data diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 9be26a3b2ff..23354f9d722 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -223,6 +223,9 @@ bpy.types.Bone.reverseMap = bpy.props.CollectionProperty(type=MocapMapping) bpy.types.Bone.foot = bpy.props.BoolProperty(name="Foot", description="Marks this bone as a 'foot', which determines retargeted animation's translation", default=False) +bpy.types.Bone.twistFix = bpy.props.BoolProperty(name="Twist Fix", + description="Fix Twist on this bone", + default=False) bpy.types.PoseBone.IKRetarget = bpy.props.BoolProperty(name="IK", description="Toggles IK Retargeting method for given bone", update=toggleIKBone, default=False) @@ -295,6 +298,7 @@ class MocapPanel(bpy.types.Panel): label_mod = "ik chain" if hasIKConstraint(pose_bone): label_mod = "ik end" + row.prop(data=bone, property='twistFix', text='', icon='RNA') row.prop(pose_bone, 'IKRetarget') row.label(label_mod) else: @@ -396,6 +400,7 @@ class OBJECT_OT_RetargetButton(bpy.types.Operator): '''Retarget animation from selected armature to active armature ''' bl_idname = "mocap.retarget" bl_label = "Retargets active action from Performer to Enduser" + bl_options = {'REGISTER', 'UNDO'} def execute(self, context): scene = context.scene -- cgit v1.2.3 From cbbbf31315bf57aed5ccfec02f29495b2e3767ec Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 15 Aug 2011 13:24:53 +0000 Subject: Restoring "Clear User Transforms" operator This can now be found as Pose -> Clear Transforms -> Reset Unkeyed, or via the operator search (known by its old name there) --- release/scripts/startup/bl_ui/space_view3d.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index c1973bc8555..c38bc0abc96 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -1262,11 +1262,15 @@ class VIEW3D_MT_pose_transform(bpy.types.Menu): layout.operator("pose.transforms_clear", text="All") + layout.separator() + layout.operator("pose.loc_clear", text="Location") layout.operator("pose.rot_clear", text="Rotation") layout.operator("pose.scale_clear", text="Scale") - layout.label(text="Origin") + layout.separator() + + layout.operator("pose.user_transforms_clear", text="Reset unkeyed") class VIEW3D_MT_pose_slide(bpy.types.Menu): -- cgit v1.2.3 From 65ca89180ac7e97c44b880f4056a956b55a671f5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 15 Aug 2011 16:25:05 +0000 Subject: fix [#28227] join_uv and bake work wrong added back ability to unwrap all selected mesh objects. --- .../startup/bl_operators/uvcalc_smart_project.py | 49 ++++++++-------------- 1 file changed, 18 insertions(+), 31 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py index 67c2f5d001b..8afd6c104e0 100644 --- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py +++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py @@ -813,39 +813,26 @@ def main(context, global RotMatStepRotation main_consts() - # TODO, all selected meshes - ''' - # objects = context.selected_editable_objects - objects = [] - - # we can will tag them later. - obList = [ob for ob in objects if ob.type == 'MESH'] - - # Face select object may not be selected. - ob = context.active_object - - if ob and (not ob.select) and ob.type == 'MESH': - # Add to the list - obList =[ob] - del objects - ''' + # Create the variables. + USER_PROJECTION_LIMIT = projection_limit + USER_ONLY_SELECTED_FACES = True + USER_SHARE_SPACE = 1 # Only for hole filling. + USER_STRETCH_ASPECT = 1 # Only for hole filling. + USER_ISLAND_MARGIN = island_margin # Only for hole filling. + USER_FILL_HOLES = 0 + USER_FILL_HOLES_QUALITY = 50 # Only for hole filling. + USER_VIEW_INIT = 0 # Only for hole filling. - # quick workaround - obList = [ob for ob in [context.active_object] if ob and ob.type == 'MESH'] + is_editmode = (context.active_object.mode == 'EDIT') + if is_editmode: + obList = [ob for ob in [context.active_object] if ob and ob.type == 'MESH'] + else: + obList = [ob for ob in context.selected_editable_objects if ob and ob.type == 'MESH'] + USER_ONLY_SELECTED_FACES = False if not obList: raise('error, no selected mesh objects') - # Create the variables. - USER_PROJECTION_LIMIT = projection_limit - USER_ONLY_SELECTED_FACES = (1) - USER_SHARE_SPACE = (1) # Only for hole filling. - USER_STRETCH_ASPECT = (1) # Only for hole filling. - USER_ISLAND_MARGIN = island_margin # Only for hole filling. - USER_FILL_HOLES = (0) - USER_FILL_HOLES_QUALITY = (50) # Only for hole filling. - USER_VIEW_INIT = (0) # Only for hole filling. - # Reuse variable if len(obList) == 1: ob = "Unwrap %i Selected Mesh" @@ -906,8 +893,8 @@ def main(context, if USER_ONLY_SELECTED_FACES: meshFaces = [thickface(f, uv_layer[i], me_verts) for i, f in enumerate(me.faces) if f.select] - #else: - # meshFaces = map(thickface, me.faces) + else: + meshFaces = [thickface(f, uv_layer[i], me_verts) for i, f in enumerate(me.faces)] if not meshFaces: continue @@ -922,7 +909,7 @@ def main(context, # meshFaces = [] # meshFaces.sort( lambda a, b: cmp(b.area , a.area) ) # Biggest first. - meshFaces.sort( key = lambda a: -a.area ) + meshFaces.sort(key=lambda a: -a.area) # remove all zero area faces while meshFaces and meshFaces[-1].area <= SMALL_NUM: -- cgit v1.2.3 From f0259542e103d306a1dac5611ccf6c1fda95f0ac Mon Sep 17 00:00:00 2001 From: Daniel Salazar Date: Tue, 16 Aug 2011 12:37:23 +0000 Subject: Front/Back togles should not disable when curve is 2D and bevel object is used http://www.pasteall.org/pic/show.php?id=16449 --- release/scripts/startup/bl_ui/properties_data_curve.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py index 7bc136c8ce0..6448b9a5229 100644 --- a/release/scripts/startup/bl_ui/properties_data_curve.py +++ b/release/scripts/startup/bl_ui/properties_data_curve.py @@ -109,7 +109,7 @@ class DATA_PT_shape_curve(CurveButtonsPanel, Panel): if (is_curve or is_text): col.label(text="Fill:") sub = col.column() - sub.active = (curve.bevel_object is None) + sub.active = (curve.dimensions == '2D' or (curve.bevel_object is None and curve.dimensions == '3D')) sub.prop(curve, "use_fill_front") sub.prop(curve, "use_fill_back") col.prop(curve, "use_fill_deform", text="Fill Deformed") -- cgit v1.2.3 From 87efb89901e36fbf72ed6f7ec0e6b6392946594f Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Tue, 16 Aug 2011 14:43:04 +0000 Subject: Py fix for trunk to pepper merge. --- release/scripts/startup/bl_ui/properties_data_armature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py index cddf9fef0f2..9a76ed81530 100644 --- a/release/scripts/startup/bl_ui/properties_data_armature.py +++ b/release/scripts/startup/bl_ui/properties_data_armature.py @@ -18,7 +18,7 @@ # import bpy -from bpy.types import Panel +from bpy.types import Panel, Menu from rna_prop_ui import PropertyPanel -- cgit v1.2.3 From 2cece7b221ebf0c1f9ae1b904d6961cb898b0eb3 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Tue, 16 Aug 2011 17:43:39 +0000 Subject: Bugfix for [#28258] [UV editor] missing snapping option. *Added back "snap_target" as we had in 2.4x. I removed the "snap_element" though, as only Vertex Snapping is supported in the UV Image Editor. --- release/scripts/startup/bl_ui/space_image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index 5d72482ce9c..2042fa1729d 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -387,7 +387,7 @@ class IMAGE_HT_header(Header): row = layout.row(align=True) row.prop(toolsettings, "use_snap", text="") - row.prop(toolsettings, "snap_element", text="", icon_only=True) + row.prop(toolsettings, "snap_target", text="") mesh = context.edit_object.data layout.prop_search(mesh.uv_textures, "active", mesh, "uv_textures", text="") -- cgit v1.2.3 From 0b7911cf0a133b60921dea07567da2d1baf2c523 Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Tue, 16 Aug 2011 19:12:36 +0000 Subject: Small change that improves usability to advanced retargeting --- release/scripts/modules/retarget.py | 43 +++++++++++++------------------------ 1 file changed, 15 insertions(+), 28 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 2c4dcbe6bda..662dfc218ab 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -483,41 +483,28 @@ def preAdvancedRetargeting(performer_obj, enduser_obj): perf_root = performer_obj.pose.bones[0].name for bone in map_bones: perf_bone = bone.bone.reverseMap[0].name - addLocalRot = False; + + cons = bone.constraints.new('COPY_ROTATION') + cons.name = "retargetTemp" + locks = bone.lock_rotation + cons.use_x = not locks[0] + cons.use_y = not locks[1] + cons.use_z = not locks[2] + cons.target = performer_obj + cons.subtarget = perf_bone + cons.target_space = 'WORLD' + cons.owner_space = 'WORLD' + if (not bone.bone.use_connect) and (perf_bone!=perf_root): - locks = bone.lock_location - #if not (locks[0] or locks[1] or locks[2]): cons = bone.constraints.new('COPY_LOCATION') cons.name = "retargetTemp" - cons.use_x = not locks[0] - cons.use_y = not locks[1] - cons.use_z = not locks[2] cons.target = performer_obj cons.subtarget = perf_bone + cons.use_x = True + cons.use_y = True + cons.use_z = True cons.target_space = 'LOCAL' cons.owner_space = 'LOCAL' - addLocalRot = True - - - cons2 = bone.constraints.new('COPY_ROTATION') - cons2.name = "retargetTemp" - locks = bone.lock_rotation - cons2.use_x = not locks[0] - cons2.use_y = not locks[1] - cons2.use_z = not locks[2] - cons2.target = performer_obj - cons2.subtarget = perf_bone - cons2.target_space = 'WORLD' - cons2.owner_space = 'WORLD' - - if perf_bone==perf_root: - addLocalRot = True - - #~ if addLocalRot: - #~ for constraint in bone.constraints: - #~ if constraint.type == 'COPY_ROTATION': - #~ constraint.target_space = 'LOCAL' - #~ constraint.owner_space = 'LOCAL' def prepareForBake(enduser_obj): -- cgit v1.2.3 From 78b147fbc20cc5cbd30057474686a5fb91124fab Mon Sep 17 00:00:00 2001 From: Benjy Cook Date: Wed, 17 Aug 2011 10:13:24 +0000 Subject: Commenting and pep8 compliance --- release/scripts/modules/mocap_tools.py | 152 ++++++++++++++++++++++----------- release/scripts/modules/retarget.py | 87 +++++-------------- release/scripts/startup/ui_mocap.py | 86 ++++++++++--------- 3 files changed, 166 insertions(+), 159 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index e5d4dcb6554..6c22f718296 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -24,7 +24,9 @@ import time from mathutils import Vector, Matrix -#Vector utility functions +# A Python implementation of n sized Vectors. +# Mathutils has a max size of 4, and we need at least 5 for Simplify Curves and even more for Cross Correlation. +# Vector utility functions class NdVector: vec = [] @@ -90,6 +92,7 @@ class NdVector: y = property(y) +#Sampled Data Point class for Simplify Curves class dataPoint: index = 0 # x,y1,y2,y3 coordinate of original point @@ -105,11 +108,19 @@ class dataPoint: self.u = u +#Cross Correlation Function +#http://en.wikipedia.org/wiki/Cross_correlation +#IN: curvesA, curvesB - bpy_collection/list of fcurves to analyze. Auto-Correlation is when they are the same. +# margin - When searching for the best "start" frame, how large a neighborhood of frames should we inspect (similar to epsilon in Calculus) +#OUT: startFrame, length of new anim, and curvesA def crossCorrelationMatch(curvesA, curvesB, margin): dataA = [] dataB = [] - end = len(curvesA[0].keyframe_points) + start, end = curvesA[0].range() + start = int(start) + end = int(end) + #transfer all fcurves data on each frame to a single NdVector. for i in range(1, end): vec = [] for fcurve in curvesA: @@ -120,9 +131,11 @@ def crossCorrelationMatch(curvesA, curvesB, margin): vec.append(fcurve.evaluate(i)) dataB.append(NdVector(vec)) + #Comparator for Cross Correlation. "Classic" implementation uses dot product, as do we. def comp(a, b): return a * b + #Create Rxy, which holds the Cross Correlation data. N = len(dataA) Rxy = [0.0] * N for i in range(N): @@ -131,7 +144,9 @@ def crossCorrelationMatch(curvesA, curvesB, margin): for j in range(i): Rxy[i] += comp(dataA[j], dataB[j - i + N]) Rxy[i] /= float(N) - def bestLocalMaximum(Rxy): + + #Find the Local maximums in the Cross Correlation data via numerical derivative. + def LocalMaximums(Rxy): Rxyd = [Rxy[i] - Rxy[i - 1] for i in range(1, len(Rxy))] maxs = [] for i in range(1, len(Rxyd) - 1): @@ -142,9 +157,12 @@ def crossCorrelationMatch(curvesA, curvesB, margin): maxs.append((i, max(Rxy[i], Rxy[i - 1]))) return [x[0] for x in maxs] #~ return max(maxs, key=lambda x: x[1])[0] - - flms = bestLocalMaximum(Rxy[0:int(len(Rxy))]) + + #flms - the possible offsets of the first part of the animation. In Auto-Corr, this is the length of the loop. + flms = LocalMaximums(Rxy[0:int(len(Rxy))]) ss = [] + + #for every local maximum, find the best one - i.e. also has the best start frame. for flm in flms: diff = [] @@ -159,20 +177,28 @@ def crossCorrelationMatch(curvesA, curvesB, margin): if errorSlice < bestSlice[1]: bestSlice = (i, errorSlice, flm) return bestSlice - + s = lowerErrorSlice(diff, margin) ss.append(s) - ss.sort(key = lambda x: x[1]) + #Find the best result and return it. + ss.sort(key=lambda x: x[1]) return ss[0][2], ss[0][0], dataA + +#Uses auto correlation (cross correlation of the same set of curves) and trims the active_object's fcurves +#Except for location curves (which in mocap tend to be not cyclic, e.g. a walk cycle forward) +#Transfers the fcurve data to a list of NdVector (length of list is number of fcurves), and calls the cross correlation function. +#Then trims the fcurve accordingly. +#IN: Nothing, set the object you want as active and call. Assumes object has animation_data.action! +#OUT: Trims the object's fcurves (except location curves). def autoloop_anim(): context = bpy.context obj = context.active_object - + def locCurve(x): x.data_path == "location" - + fcurves = [x for x in obj.animation_data.action.fcurves if not locCurve(x)] margin = 10 @@ -180,13 +206,10 @@ def autoloop_anim(): flm, s, data = crossCorrelationMatch(fcurves, fcurves, margin) loop = data[s:s + flm] - #find *all* loops, s:s+flm, s+flm:s+2flm, etc... - #and interpolate between all - # to find "the perfect loop". - #Maybe before finding s? interp(i,i+flm,i+2flm).... - #~ for i in range(1, margin + 1): - #~ w1 = sqrt(float(i) / margin) - #~ loop[-i] = (loop[-i] * w1) + (loop[0] * (1 - w1)) + #performs blending with a root falloff on the seam's neighborhood to ensure good tiling. + for i in range(1, margin + 1): + w1 = sqrt(float(i) / margin) + loop[-i] = (loop[-i] * w1) + (loop[0] * (1 - w1)) for curve in fcurves: pts = curve.keyframe_points @@ -201,8 +224,16 @@ def autoloop_anim(): context.scene.frame_end = flm +#simplifyCurves: performes the bulk of the samples to bezier conversion. +#IN: curveGroup - which can be a collection of singleFcurves, or grouped (via nested lists) . +# error - threshold of permittable error (max distance) of the new beziers to the original data +# reparaError - threshold of error where we should try to fix the parameterization rather than split the existing curve. > error, usually by a small constant factor for best performance. +# maxIterations - maximum number of iterations of reparameterizations we should attempt. (Newton-Rahpson is not guarenteed to converge, so this is needed). +# group_mode - boolean, indicating wether we should place bezier keyframes on the same x (frame), or optimize each individual curve. +#OUT: None. Deletes the existing curves and creates the new beziers. def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): + #Calculates the unit tangent of point v def unitTangent(v, data_pts): tang = NdVector((0, 0, 0, 0, 0)) if v != 0: @@ -214,7 +245,8 @@ def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): tang.normalize() return tang - #assign parametric u value for each point in original data + #assign parametric u value for each point in original data, via relative arc length + #http://en.wikipedia.org/wiki/Arc_length def chordLength(data_pts, s, e): totalLength = 0 for pt in data_pts[s:e + 1]: @@ -230,7 +262,7 @@ def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): print(s, e) pt.u = (pt.temp / totalLength) - # get binomial coefficient, this function/table is only called with args + # get binomial coefficient lookup table, this function/table is only called with args # (3,0),(3,1),(3,2),(3,3),(2,0),(2,1),(2,2)! binomDict = {(3, 0): 1, (3, 1): 3, @@ -239,8 +271,8 @@ def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): (2, 0): 1, (2, 1): 2, (2, 2): 1} - #value at pt t of a single bernstein Polynomial + #value at pt t of a single bernstein Polynomial def bernsteinPoly(n, i, t): binomCoeff = binomDict[(n, i)] return binomCoeff * pow(t, i) * pow(1 - t, n - i) @@ -380,6 +412,7 @@ def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): fud = 1 pt.u = pt.u - (fu / fud) + #Create data_pts, a list of dataPoint type, each is assigned index i, and an NdVector def createDataPts(curveGroup, group_mode): data_pts = [] if group_mode: @@ -403,6 +436,7 @@ def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): data_pts.append(dataPoint(i, NdVector((x, y1, y2, y3, y4)))) return data_pts + #Recursively fit cubic beziers to the data_pts between s and e def fitCubic(data_pts, s, e): # if there are less than 3 points, fit a single basic bezier if e - s < 3: @@ -437,6 +471,7 @@ def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): beziers.append(bez) return + # deletes the sampled points and creates beziers. def createNewCurves(curveGroup, beziers, group_mode): #remove all existing data points if group_mode: @@ -483,15 +518,14 @@ def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): #remove old Fcurves and insert the new ones createNewCurves(curveGroup, beziers, group_mode) -#Main function of simplification -#sel_opt: either "sel" or "all" for which curves to effect -#error: maximum error allowed, in fraction (20% = 0.0020), -#i.e. divide by 10000 from percentage wanted. -#group_mode: boolean, to analyze each curve seperately or in groups, -#where group is all curves that effect the same property -#(e.g. a bone's x,y,z rotation) - +#Main function of simplification, which called by Operator +#IN: +# sel_opt- either "sel" (selected) or "all" for which curves to effect +# error- maximum error allowed, in fraction (20% = 0.0020, which is the default), +# i.e. divide by 10000 from percentage wanted. +# group_mode- boolean, to analyze each curve seperately or in groups, +# where a group is all curves that effect the same property/RNA path def fcurves_simplify(context, obj, sel_opt="all", error=0.002, group_mode=True): # main vars fcurves = obj.animation_data.action.fcurves @@ -533,11 +567,12 @@ def fcurves_simplify(context, obj, sel_opt="all", error=0.002, group_mode=True): return + # Implementation of non-linear median filter, with variable kernel size -# Double pass - one marks spikes, the other smooths one +# Double pass - one marks spikes, the other smooths them # Expects sampled keyframes on everyframe - - +# IN: None. Performs the operations on the active_object's fcurves. Expects animation_data.action to exist! +# OUT: None. Fixes the fcurves "in-place". def denoise_median(): context = bpy.context obj = context.active_object @@ -568,6 +603,9 @@ def denoise_median(): return +# Recieves armature, and rotations all bones by 90 degrees along the X axis +# This fixes the common axis issue BVH files have when importing. +# IN: Armature (bpy.types.Armature) def rotate_fix_armature(arm_data): global_matrix = Matrix.Rotation(radians(90), 4, "X") bpy.ops.object.mode_set(mode='EDIT', toggle=False) @@ -588,6 +626,8 @@ def rotate_fix_armature(arm_data): bpy.ops.object.mode_set(mode='OBJECT', toggle=False) +#Roughly scales the performer armature to match the enduser armature +#IN: perfromer_obj, enduser_obj, Blender objects whose .data is an armature. def scale_fix_armature(performer_obj, enduser_obj): perf_bones = performer_obj.data.bones end_bones = enduser_obj.data.bones @@ -611,6 +651,8 @@ def scale_fix_armature(performer_obj, enduser_obj): performer_obj.scale *= factor +#Guess Mapping +#Given a performer and enduser armature, attempts to guess the hiearchy mapping def guessMapping(performer_obj, enduser_obj): perf_bones = performer_obj.data.bones end_bones = enduser_obj.data.bones @@ -642,11 +684,16 @@ def guessMapping(performer_obj, enduser_obj): def guessSingleMapping(perf_bone): possible_bones = [end_bones[0]] + while possible_bones: for end_bone in possible_bones: match = nameMatch(perf_bone.name, end_bone.name) if match == 2 and not perf_bone.map: perf_bone.map = end_bone.name + #~ elif match == 1 and not perf_bone.map: + #~ oppo = perf_bones[oppositeBone(perf_bone)].map + # if oppo: + # perf_bone = oppo newPossibleBones = [] for end_bone in possible_bones: newPossibleBones += list(end_bone.children) @@ -658,6 +705,9 @@ def guessMapping(performer_obj, enduser_obj): guessSingleMapping(root) +# Creates limit rotation constraints on the enduser armature based on range of motion (max min of fcurves) of the performer. +# IN: context (bpy.context, etc.), and 2 blender objects which are armatures +# OUT: creates the limit constraints. def limit_dof(context, performer_obj, enduser_obj): limitDict = {} perf_bones = [bone for bone in performer_obj.pose.bones if bone.bone.map] @@ -705,18 +755,10 @@ def limit_dof(context, performer_obj, enduser_obj): newCons.use_limit_x = True newCons.use_limit_y = True newCons.use_limit_z = True - #~ else: - #~ bone.ik_min_x, bone.ik_min_y, bone.ik_min_z, bone.ik_max_x, bone.ik_max_y, bone.ik_max_z = limitDict[bone.name] - #~ bone.use_ik_limit_x = True - #~ bone.use_ik_limit_y = True - #~ bone.use_ik_limit_z= True - #~ bone.ik_stiffness_x = 1/((limitDict[bone.name][3] - limitDict[bone.name][0])/(2*pi))) - #~ bone.ik_stiffness_y = 1/((limitDict[bone.name][4] - limitDict[bone.name][1])/(2*pi))) - #~ bone.ik_stiffness_z = 1/((limitDict[bone.name][5] - limitDict[bone.name][2])/(2*pi))) - context.scene.frame_set(c_frame) +# Removes the constraints that were added by limit_dof on the enduser_obj def limit_dof_toggle_off(context, enduser_obj): for bone in enduser_obj.pose.bones: existingConstraint = [constraint for constraint in bone.constraints if constraint.name == "DOF Limitation"] @@ -724,6 +766,8 @@ def limit_dof_toggle_off(context, enduser_obj): bone.constraints.remove(existingConstraint[0]) +# Reparameterizes a blender path via keyframing it's eval_time to match a stride_object's forward velocity. +# IN: Context, stride object (blender object with location keyframes), path object. def path_editing(context, stride_obj, path): y_fcurve = [fcurve for fcurve in stride_obj.animation_data.action.fcurves if fcurve.data_path == "location"][1] s, e = context.scene.frame_start, context.scene.frame_end # y_fcurve.range() @@ -771,11 +815,14 @@ def path_editing(context, stride_obj, path): print("finished path editing") +#Animation Stitching +#Stitches two retargeted animations together via NLA settings. +#IN: enduser_obj, a blender armature that has had two retargets applied. def anim_stitch(context, enduser_obj): stitch_settings = enduser_obj.data.stitch_settings action_1 = stitch_settings.first_action action_2 = stitch_settings.second_action - if stitch_settings.stick_bone!="": + if stitch_settings.stick_bone != "": selected_bone = enduser_obj.pose.bones[stitch_settings.stick_bone] else: selected_bone = enduser_obj.pose.bones[0] @@ -791,8 +838,8 @@ def anim_stitch(context, enduser_obj): mocapStrip = mocapTrack.strips.new(TrackNamesB.base_track, stitch_settings.blend_frame, mocapAction) mocapStrip.extrapolation = "HOLD_FORWARD" mocapStrip.blend_in = stitch_settings.blend_amount - mocapStrip.action_frame_start+=stitch_settings.second_offset - mocapStrip.action_frame_end+=stitch_settings.second_offset + mocapStrip.action_frame_start += stitch_settings.second_offset + mocapStrip.action_frame_end += stitch_settings.second_offset constraintTrack = anim_data.nla_tracks.new() constraintTrack.name = TrackNamesB.auto_fix_track constraintAction = bpy.data.actions[TrackNamesB.auto_fix_track] @@ -821,8 +868,8 @@ def anim_stitch(context, enduser_obj): actionBTrack = stride_anim_data.nla_tracks.new() actionBTrack.name = TrackNamesB.stride_action actionBStrip = actionBTrack.strips.new(TrackNamesB.stride_action, stitch_settings.blend_frame, bpy.data.actions[TrackNamesB.stride_action]) - actionBStrip.action_frame_start+=stitch_settings.second_offset - actionBStrip.action_frame_end+=stitch_settings.second_offset + actionBStrip.action_frame_start += stitch_settings.second_offset + actionBStrip.action_frame_end += stitch_settings.second_offset actionBStrip.blend_in = stitch_settings.blend_amount actionBStrip.extrapolation = "NOTHING" #we need to change the stride_bone's action to add the offset @@ -831,15 +878,16 @@ def anim_stitch(context, enduser_obj): scene.frame_set(stitch_settings.blend_frame) actual_pos = (selected_bone.matrix.to_translation() * enduser_obj.matrix_world) offset = actual_pos - desired_pos - - for i,fcurve in enumerate([fcurve for fcurve in bpy.data.actions[TrackNamesB.stride_action].fcurves if fcurve.data_path=="location"]): - print(offset[i],i,fcurve.array_index) + + for i, fcurve in enumerate([fcurve for fcurve in bpy.data.actions[TrackNamesB.stride_action].fcurves if fcurve.data_path == "location"]): + print(offset[i], i, fcurve.array_index) for pt in fcurve.keyframe_points: - pt.co.y-=offset[i] - pt.handle_left.y-=offset[i] - pt.handle_right.y-=offset[i] + pt.co.y -= offset[i] + pt.handle_left.y -= offset[i] + pt.handle_right.y -= offset[i] +#Guesses setting for animation stitching via Cross Correlation def guess_anim_stitch(context, enduser_obj): stitch_settings = enduser_obj.data.stitch_settings action_1 = stitch_settings.first_action @@ -851,6 +899,6 @@ def guess_anim_stitch(context, enduser_obj): curvesA = mocapA.fcurves curvesB = mocapB.fcurves flm, s, data = crossCorrelationMatch(curvesA, curvesB, 10) - print(flm,s) + print("Guessed the following for start and offset: ", s, flm) enduser_obj.data.stitch_settings.blend_frame = flm - enduser_obj.data.stitch_settings.second_offset = s \ No newline at end of file + enduser_obj.data.stitch_settings.second_offset = s diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 662dfc218ab..67e8c7da55d 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -22,7 +22,6 @@ import bpy from mathutils import * from math import radians, acos, pi from bl_operators import nla -import cProfile def hasIKConstraint(pose_bone): @@ -53,8 +52,8 @@ def createDictionary(perf_arm, end_arm): feetBones = [bone.name for bone in perf_arm.bones if bone.foot] return feetBones, root -def loadMapping(perf_arm, end_arm): +def loadMapping(perf_arm, end_arm): for end_bone in end_arm.bones: #find its match and add perf_bone to the match's mapping if end_bone.reverseMap: @@ -80,17 +79,7 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene perf_world_rotation = perf_bone.matrix inter_world_base_rotation = inter_bone.bone.matrix_local inter_world_base_inv = inter_world_base_rotation.inverted() - bake_matrix = (inter_world_base_inv.to_3x3() * perf_world_rotation.to_3x3()) - #~ orgEul = inter_bone.bone.matrix_local.to_euler("XYZ") - #~ eul = bake_matrix.to_euler("XYZ", orgEul) - #~ diff = -bake_matrix.to_euler().y + inter_bone.bone.matrix.to_euler().y - #~ eul.rotate_axis("Y", diff) - #~ eul.make_compatible(orgEul) - #~ bake_matrix = eul.to_matrix() - #~ #diff = abs(diff) - #bake_matrix = bake_matrix* Matrix.Rotation(pi/2, 3, "Y") - #~ scene = bpy.context.scene - #~ print(scene.frame_current, inter_bone.name, bake_matrix.to_euler().y) + bake_matrix = (inter_world_base_inv.to_3x3() * perf_world_rotation.to_3x3()) return bake_matrix.to_4x4() #uses 1to1 and interpolation/averaging to match many to 1 retarget @@ -117,6 +106,7 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene else: perf_bone = performer_bones[perf_bone_name[0].name] inter_bone.matrix_basis = singleBoneRetarget(inter_bone, perf_bone) + #Some bones have incorrect roll on the source armature, and need to be marked for fixing if inter_bone.bone.twistFix: inter_bone.matrix_basis *= Matrix.Rotation(radians(180), 4, "Y") rot_mode = inter_bone.rotation_mode @@ -151,7 +141,6 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene bone.roll = 0 #resets roll print("retargeting to intermediate") - #bpy.ops.armature.calculate_roll(type='Z') bpy.ops.object.mode_set(mode="OBJECT") inter_obj.data.name = "inter_arm" inter_arm = inter_obj.data @@ -187,6 +176,7 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene, step) inter_bones = inter_obj.pose.bones end_bones = enduser_obj.pose.bones + #Basic "visual baking" function, for transfering rotations from intermediate to end user def bakeTransform(end_bone): src_bone = inter_bones[end_bone.name] trg_bone = end_bone @@ -265,29 +255,21 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame # now we take our locDict and analyze it. # we need to derive all chains - + def locDeriv(key, t): graph = locDict[key] return graph[t + 1] - graph[t] - #~ locDeriv = {} - #~ for key in locDictKeys: - #~ locDeriv[key] = [] - - #~ for key in locDict.keys(): - #~ graph = locDict[key] - #~ locDeriv[key] = [graph[t + 1] - graph[t] for t in range(len(graph) - 1)] - # now find the plant frames, where perfFeet don't move much linearAvg = [] for key in perfFeet: for i in range(len(locDict[key]) - 1): - v = locDeriv(key,i) + v = locDeriv(key, i) if (v.length < 0.1): - hipV = locDeriv(perfRoot,i) - endV = locDeriv(perf_bones[key].bone.map,i) + hipV = locDeriv(perfRoot, i) + endV = locDeriv(perf_bones[key].bone.map, i) #this is a plant frame. #lets see what the original hip delta is, and the corresponding #end bone's delta @@ -312,7 +294,7 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame #determine the average change in scale needed avg = sum(linearAvg) / len(linearAvg) scene.frame_set(s_frame) - initialPos = (tailLoc(perf_bones[perfRoot]) / avg) #+ stride_bone.location + initialPos = (tailLoc(perf_bones[perfRoot]) / avg) for t in range(s_frame, e_frame): scene.frame_set(t) #calculate the new position, by dividing by the found ratio between performer and enduser @@ -320,7 +302,6 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame stride_bone.location = enduser_obj_mat * (newTranslation - initialPos) stride_bone.keyframe_insert("location") else: - stride_bone.keyframe_insert("location") stride_bone.animation_data.action.name = ("Stride Bone " + action_name) @@ -342,7 +323,7 @@ def IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene, step): bpy.ops.object.mode_set(mode='OBJECT') if not ik_constraint.target: ik_constraint.target = enduser_obj - ik_constraint.subtarget = pose_bone.name+"IK" + ik_constraint.subtarget = pose_bone.name + "IK" target = orgLocTrg # There is a target now @@ -370,14 +351,6 @@ def IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene, step): def turnOffIK(enduser_obj): end_bones = enduser_obj.pose.bones for pose_bone in end_bones: - if pose_bone.is_in_ik_chain: - pass - # TODO: - # set stiffness according to place on chain - # and values from analysis that is stored in the bone - #pose_bone.ik_stiffness_x = 0.5 - #pose_bone.ik_stiffness_y = 0.5 - #pose_bone.ik_stiffness_z = 0.5 ik_constraint = hasIKConstraint(pose_bone) if ik_constraint: ik_constraint.mute = True @@ -412,18 +385,14 @@ def originalLocationTarget(end_bone, enduser_obj): if not end_bone.name + "IK" in enduser_obj.data.bones: newBone = enduser_obj.data.edit_bones.new(end_bone.name + "IK") newBone.head = end_bone.tail - newBone.tail = end_bone.tail + Vector((0,0.1,0)) - #~ empty = bpy.context.active_object - #~ empty.name = end_bone.name + "Org" - #~ empty.empty_draw_size = 0.1 - #~ empty.parent = enduser_obj + newBone.tail = end_bone.tail + Vector((0, 0.1, 0)) else: newBone = enduser_obj.pose.bones[end_bone.name + "IK"] return newBone #create the specified NLA setup for base animation, constraints and tweak layer. -def NLASystemInitialize(enduser_arm, context):#enduser_obj, name): +def NLASystemInitialize(enduser_arm, context): enduser_obj = context.active_object NLATracks = enduser_arm.mocapNLATracks[enduser_obj.data.active_mocap] name = NLATracks.name @@ -461,9 +430,8 @@ def NLASystemInitialize(enduser_arm, context):#enduser_obj, name): userAction.use_fake_user = True userStrip = userTrack.strips.new("Manual fixes " + name, s_frame, userAction) userStrip.extrapolation = "HOLD" - #userStrip.blend_type = "MULITPLY" - doesn't work due to work, will be activated soon + userStrip.blend_type = "ADD" anim_data.nla_tracks.active = constraintTrack - #anim_data.action = constraintAction anim_data.action_extrapolation = "NOTHING" #set the stride_bone's action if "stride_bone" in bpy.data.objects: @@ -494,8 +462,8 @@ def preAdvancedRetargeting(performer_obj, enduser_obj): cons.subtarget = perf_bone cons.target_space = 'WORLD' cons.owner_space = 'WORLD' - - if (not bone.bone.use_connect) and (perf_bone!=perf_root): + + if (not bone.bone.use_connect) and (perf_bone != perf_root): cons = bone.constraints.new('COPY_LOCATION') cons.name = "retargetTemp" cons.target = performer_obj @@ -517,6 +485,7 @@ def prepareForBake(enduser_obj): if "retargetTemp" in cons.name: bone.bone.select = True + def cleanTempConstraints(enduser_obj): bones = enduser_obj.pose.bones map_bones = [bone for bone in bones if bone.bone.reverseMap] @@ -525,6 +494,7 @@ def cleanTempConstraints(enduser_obj): if "retargetTemp" in cons.name: bone.constraints.remove(cons) + #Main function that runs the retargeting sequence. #If advanced == True, we assume constraint's were already created def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): @@ -532,13 +502,13 @@ def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): end_arm = enduser_obj.data advanced = end_arm.advancedRetarget step = end_arm.frameStep - + try: enduser_obj.animation_data.action = bpy.data.actions.new("temp") enduser_obj.animation_data.action.use_fake_user = True except: print("no need to create new action") - + print("creating Dictionary") feetBones, root = createDictionary(perf_arm, end_arm) print("cleaning stuff up") @@ -576,22 +546,6 @@ def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): NLATracks = end_arm.mocapNLATracks[name] end_arm.active_mocap = name print("retargeting done!") - -def profileWrapper(): - context = bpy.context - scene = context.scene - s_frame = scene.frame_start - e_frame = scene.frame_end - enduser_obj = context.active_object - performer_obj = [obj for obj in context.selected_objects if obj != enduser_obj] - if enduser_obj is None or len(performer_obj) != 1: - print("Need active and selected armatures") - else: - performer_obj = performer_obj[0] - s_frame, e_frame = performer_obj.animation_data.action.frame_range - s_frame = int(s_frame) - e_frame = int(e_frame) - totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame) def isRigAdvanced(enduser_obj): @@ -603,6 +557,3 @@ def isRigAdvanced(enduser_obj): if enduser_obj.data.animation_data: if enduser_obj.data.animation_data.drivers: return True - -if __name__ == "__main__": - cProfile.run("profileWrapper()") diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 23354f9d722..3cb33776b0b 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -112,6 +112,7 @@ bpy.utils.register_class(MocapConstraint) bpy.types.Armature.mocap_constraints = bpy.props.CollectionProperty(type=MocapConstraint) +# Animation Stitch Settings, used for animation stitching of 2 retargeted animations. class AnimationStitchSettings(bpy.types.PropertyGroup): first_action = bpy.props.StringProperty(name="Action 1", description="First action in stitch") @@ -132,6 +133,7 @@ class AnimationStitchSettings(bpy.types.PropertyGroup): bpy.utils.register_class(AnimationStitchSettings) +# MocapNLA Tracks. Stores which tracks/actions are associated with each retargeted animation. class MocapNLATracks(bpy.types.PropertyGroup): name = bpy.props.StringProperty() base_track = bpy.props.StringProperty() @@ -141,7 +143,8 @@ class MocapNLATracks(bpy.types.PropertyGroup): bpy.utils.register_class(MocapNLATracks) - + +#Update function for Advanced Retarget boolean variable. def advancedRetargetToggle(self, context): enduser_obj = context.active_object performer_obj = [obj for obj in context.selected_objects if obj != enduser_obj] @@ -156,20 +159,23 @@ def advancedRetargetToggle(self, context): retarget.cleanTempConstraints(enduser_obj) - +#Animation Stitch Settings Property bpy.types.Armature.stitch_settings = bpy.props.PointerProperty(type=AnimationStitchSettings) -bpy.types.Armature.active_mocap = bpy.props.StringProperty(update=retarget.NLASystemInitialize) +#Current/Active retargeted animation on the armature +bpy.types.Armature.active_mocap = bpy.props.StringProperty(update=retarget.NLASystemInitialize) +#Collection of retargeted animations and their NLA Tracks on the armature bpy.types.Armature.mocapNLATracks = bpy.props.CollectionProperty(type=MocapNLATracks) +#Advanced retargeting boolean property bpy.types.Armature.advancedRetarget = bpy.props.BoolProperty(default=False, update=advancedRetargetToggle) +#frame step - frequency of frames to retarget. Skipping is useful for previewing, faster work etc. bpy.types.Armature.frameStep = smooth_out = bpy.props.IntProperty(name="Frame Skip", default=1, description="Amount of frames to skip - for previewing retargets quickly. 1 is fully sampled", min=1) -#Update function for IK functionality. Is called when IK prop checkboxes are toggled. - def toggleIKBone(self, context): + #Update function for IK functionality. Is called when IK prop checkboxes are toggled. if self.IKRetarget: if not self.is_in_ik_chain: print(self.name + " IK toggled ON!") @@ -211,21 +217,29 @@ def toggleIKBone(self, context): for bone in cnstrn_bone.parent_recursive: if not bone.is_in_ik_chain: bone.IKRetarget = False - + +#MocapMap class for storing mapping on enduser performer, +# where a bone may be linked to more than one on the performer class MocapMapping(bpy.types.PropertyGroup): name = bpy.props.StringProperty() bpy.utils.register_class(MocapMapping) +#string property for storing performer->enduser mapping bpy.types.Bone.map = bpy.props.StringProperty() +#Collection Property for storing enduser->performer mapping bpy.types.Bone.reverseMap = bpy.props.CollectionProperty(type=MocapMapping) +#Boolean property for storing foot bone toggle bpy.types.Bone.foot = bpy.props.BoolProperty(name="Foot", description="Marks this bone as a 'foot', which determines retargeted animation's translation", default=False) +#Boolean property for storing if this bone is twisted along the y axis, +# which can happen due to various sources of performers bpy.types.Bone.twistFix = bpy.props.BoolProperty(name="Twist Fix", description="Fix Twist on this bone", default=False) +#Boolean property for toggling ik retargeting for this bone bpy.types.PoseBone.IKRetarget = bpy.props.BoolProperty(name="IK", description="Toggles IK Retargeting method for given bone", update=toggleIKBone, default=False) @@ -384,7 +398,7 @@ class ExtraToolsPanel(bpy.types.Panel): if activeIsArmature: enduser_arm = context.active_object.data layout.label("Retargeted Animations:") - layout.prop_search(enduser_arm, "active_mocap",enduser_arm, "mocapNLATracks") + layout.prop_search(enduser_arm, "active_mocap", enduser_arm, "mocapNLATracks") settings = enduser_arm.stitch_settings layout.prop_search(settings, "first_action", enduser_arm, "mocapNLATracks") layout.prop_search(settings, "second_action", enduser_arm, "mocapNLATracks") @@ -397,6 +411,8 @@ class ExtraToolsPanel(bpy.types.Panel): class OBJECT_OT_RetargetButton(bpy.types.Operator): + #Retargeting operator. Assumes selected and active armatures, where the performer (the selected one) + # has an action for retargeting '''Retarget animation from selected armature to active armature ''' bl_idname = "mocap.retarget" bl_label = "Retargets active action from Performer to Enduser" @@ -428,41 +444,13 @@ class OBJECT_OT_RetargetButton(bpy.types.Operator): activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) performer_obj = [obj for obj in context.selected_objects if obj != context.active_object] if performer_obj: - return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) + return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) and performer_obj[0].animation_data else: return False - - - #~ class OBJECT_OT_AdvancedRetargetButton(bpy.types.Operator): - #~ '''Prepare for advanced retargeting ''' - #~ bl_idname = "mocap.preretarget" - #~ bl_label = "Prepares retarget of active action from Performer to Enduser" - - #~ def execute(self, context): - #~ scene = context.scene - #~ s_frame = scene.frame_start - #~ e_frame = scene.frame_end - #~ enduser_obj = context.active_object - #~ performer_obj = [obj for obj in context.selected_objects if obj != enduser_obj] - #~ if enduser_obj is None or len(performer_obj) != 1: - #~ print("Need active and selected armatures") - #~ else: - #~ performer_obj = performer_obj[0] - #~ retarget.preAdvancedRetargeting(performer_obj, enduser_obj) - #~ return {"FINISHED"} - - #~ @classmethod - #~ def poll(cls, context): - #~ if context.active_object: - #~ activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) - #~ performer_obj = [obj for obj in context.selected_objects if obj != context.active_object] - #~ if performer_obj: - #~ return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) - #~ else: - #~ return False class OBJECT_OT_SaveMappingButton(bpy.types.Operator): + #Operator for saving mapping to enduser armature '''Save mapping to active armature (for future retargets) ''' bl_idname = "mocap.savemapping" bl_label = "Saves user generated mapping from Performer to Enduser" @@ -486,6 +474,7 @@ class OBJECT_OT_SaveMappingButton(bpy.types.Operator): class OBJECT_OT_LoadMappingButton(bpy.types.Operator): '''Load saved mapping from active armature''' + #Operator for loading mapping to enduser armature bl_idname = "mocap.loadmapping" bl_label = "Loads user generated mapping from Performer to Enduser" @@ -504,9 +493,10 @@ class OBJECT_OT_LoadMappingButton(bpy.types.Operator): return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) else: return False - + class OBJECT_OT_SelectMapBoneButton(bpy.types.Operator): + #Operator for setting selected bone in enduser armature to the performer mapping '''Select a bone for faster mapping''' bl_idname = "mocap.selectmap" bl_label = "Select a bone for faster mapping" @@ -538,6 +528,7 @@ class OBJECT_OT_SelectMapBoneButton(bpy.types.Operator): class OBJECT_OT_ConvertSamplesButton(bpy.types.Operator): + #Operator to convert samples to beziers on the selected object '''Convert active armature's sampled keyframed to beziers''' bl_idname = "mocap.samples" bl_label = "Converts samples / simplifies keyframes to beziers" @@ -552,6 +543,7 @@ class OBJECT_OT_ConvertSamplesButton(bpy.types.Operator): class OBJECT_OT_LooperButton(bpy.types.Operator): + #Operator to trim fcurves which contain a few loops to a single one on the selected object '''Trim active armature's animation to a single cycle, given a cyclic animation (such as a walk cycle)''' bl_idname = "mocap.looper" bl_label = "loops animation / sampled mocap data" @@ -566,6 +558,7 @@ class OBJECT_OT_LooperButton(bpy.types.Operator): class OBJECT_OT_DenoiseButton(bpy.types.Operator): + #Operator to denoise impluse noise on the active object's fcurves '''Denoise active armature's animation. Good for dealing with 'bad' frames inherent in mocap animation''' bl_idname = "mocap.denoise" bl_label = "Denoises sampled mocap data " @@ -584,6 +577,7 @@ class OBJECT_OT_DenoiseButton(bpy.types.Operator): class OBJECT_OT_LimitDOFButton(bpy.types.Operator): + #Operator to analyze performer armature and apply rotation constraints on the enduser armature '''Create limit constraints on the active armature from the selected armature's animation's range of motion''' bl_idname = "mocap.limitdof" bl_label = "Analyzes animations Max/Min DOF and adds hard/soft constraints" @@ -605,6 +599,7 @@ class OBJECT_OT_LimitDOFButton(bpy.types.Operator): class OBJECT_OT_RemoveLimitDOFButton(bpy.types.Operator): + #Removes constraints created by above operator '''Removes previously created limit constraints on the active armature''' bl_idname = "mocap.removelimitdof" bl_label = "Removes previously created limit constraints on the active armature" @@ -622,6 +617,7 @@ class OBJECT_OT_RemoveLimitDOFButton(bpy.types.Operator): class OBJECT_OT_RotateFixArmature(bpy.types.Operator): + #Operator to fix common imported Mocap data issue of wrong axis system on active object '''Realign the active armature's axis system to match Blender (Commonly needed after bvh import)''' bl_idname = "mocap.rotate_fix" bl_label = "Rotates selected armature 90 degrees (fix for bvh import)" @@ -637,6 +633,7 @@ class OBJECT_OT_RotateFixArmature(bpy.types.Operator): class OBJECT_OT_ScaleFixArmature(bpy.types.Operator): + #Operator to scale down the selected armature to match the active one '''Rescale selected armature to match the active animation, for convienence''' bl_idname = "mocap.scale_fix" bl_label = "Scales performer armature to match target armature" @@ -659,6 +656,7 @@ class OBJECT_OT_ScaleFixArmature(bpy.types.Operator): class MOCAP_OT_AddMocapFix(bpy.types.Operator): + #Operator to add a post-retarget fix '''Add a post-retarget fix - useful for fixing certain artifacts following the retarget''' bl_idname = "mocap.addmocapfix" bl_label = "Add Mocap Fix to target armature" @@ -683,6 +681,7 @@ class MOCAP_OT_AddMocapFix(bpy.types.Operator): class OBJECT_OT_RemoveMocapConstraint(bpy.types.Operator): + #Operator to remove a post-retarget fix '''Remove this post-retarget fix''' bl_idname = "mocap.removeconstraint" bl_label = "Removes fixes from target armature" @@ -707,6 +706,7 @@ class OBJECT_OT_RemoveMocapConstraint(bpy.types.Operator): class OBJECT_OT_BakeMocapConstraints(bpy.types.Operator): + #Operator to bake all post-retarget fixes '''Bake all post-retarget fixes to the Retarget Fixes NLA Track''' bl_idname = "mocap.bakeconstraints" bl_label = "Bake all fixes to target armature" @@ -722,6 +722,7 @@ class OBJECT_OT_BakeMocapConstraints(bpy.types.Operator): class OBJECT_OT_UnbakeMocapConstraints(bpy.types.Operator): + #Operator to unbake all post-retarget fixes '''Unbake all post-retarget fixes - removes the baked data from the Retarget Fixes NLA Track''' bl_idname = "mocap.unbakeconstraints" bl_label = "Unbake all fixes to target armature" @@ -737,6 +738,8 @@ class OBJECT_OT_UnbakeMocapConstraints(bpy.types.Operator): class OBJECT_OT_UpdateMocapConstraints(bpy.types.Operator): + #Operator to update all post-retarget fixes, similar to update dependencies on drivers + #Needed because python properties lack certain callbacks and some fixes take a while to recalculate. '''Updates all post-retarget fixes - needed after changes to armature object or pose''' bl_idname = "mocap.updateconstraints" bl_label = "Updates all fixes to target armature - neccesary to take under consideration changes to armature object or pose" @@ -752,6 +755,7 @@ class OBJECT_OT_UpdateMocapConstraints(bpy.types.Operator): class OBJECT_OT_GuessHierachyMapping(bpy.types.Operator): + #Operator which calls heurisitic function to guess mapping between 2 armatures '''Attemps to auto figure out hierarchy mapping''' bl_idname = "mocap.guessmapping" bl_label = "Attemps to auto figure out hierarchy mapping" @@ -774,6 +778,7 @@ class OBJECT_OT_GuessHierachyMapping(bpy.types.Operator): class OBJECT_OT_PathEditing(bpy.types.Operator): + #Operator which calls path editing function, making active object follow the selected curve. '''Sets active object (stride object) to follow the selected curve''' bl_idname = "mocap.pathediting" bl_label = "Sets active object (stride object) to follow the selected curve" @@ -793,6 +798,7 @@ class OBJECT_OT_PathEditing(bpy.types.Operator): class OBJECT_OT_AnimationStitchingButton(bpy.types.Operator): + #Operator which calls stitching function, combining 2 animations onto the NLA. '''Stitches two defined animations into a single one via alignment of NLA Tracks''' bl_idname = "mocap.animstitch" bl_label = "Stitches two defined animations into a single one via alignment of NLA Tracks" @@ -810,9 +816,10 @@ class OBJECT_OT_AnimationStitchingButton(bpy.types.Operator): stitch_settings = context.active_object.data.stitch_settings return (stitch_settings.first_action and stitch_settings.second_action) return False - + class OBJECT_OT_GuessAnimationStitchingButton(bpy.types.Operator): + #Operator which calls stitching function heuristic, setting good values for above operator. '''Guesses the stitch frame and second offset for animation stitch''' bl_idname = "mocap.animstitchguess" bl_label = "Guesses the stitch frame and second offset for animation stitch" @@ -831,6 +838,7 @@ class OBJECT_OT_GuessAnimationStitchingButton(bpy.types.Operator): return (stitch_settings.first_action and stitch_settings.second_action) return False + def register(): bpy.utils.register_module(__name__) -- cgit v1.2.3 From 2bd016fe3f08524711d1d45e8ebf12d483c6131c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 18 Aug 2011 12:20:10 +0000 Subject: formatting edits, no functional changes. --- release/scripts/startup/bl_operators/wm.py | 248 ++++++++++++++++++++--------- 1 file changed, 176 insertions(+), 72 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index fe75c54e60e..b898d3fbf80 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -20,8 +20,12 @@ import bpy from bpy.types import Menu, Operator -from bpy.props import StringProperty, BoolProperty, IntProperty, \ - FloatProperty, EnumProperty +from bpy.props import (StringProperty, + BoolProperty, + IntProperty, + FloatProperty, + EnumProperty, + ) from rna_prop_ui import rna_idprop_ui_prop_get, rna_idprop_ui_prop_clear @@ -39,15 +43,23 @@ class MESH_OT_delete_edgeloop(Operator): return {'CANCELLED'} -rna_path_prop = StringProperty(name="Context Attributes", - description="rna context string", maxlen=1024, default="") +rna_path_prop = StringProperty( + name="Context Attributes", + description="rna context string", + maxlen=1024, + ) -rna_reverse_prop = BoolProperty(name="Reverse", - description="Cycle backwards", default=False) +rna_reverse_prop = BoolProperty( + name="Reverse", + description="Cycle backwards", + default=False, + ) -rna_relative_prop = BoolProperty(name="Relative", +rna_relative_prop = BoolProperty( + name="Relative", description="Apply relative to the current value (delta)", - default=False) + default=False, + ) def context_path_validate(context, data_path): @@ -82,15 +94,21 @@ class BRUSH_OT_active_index_set(Operator): bl_idname = "brush.active_index_set" bl_label = "Set Brush Number" - mode = StringProperty(name="mode", - description="Paint mode to set brush for", maxlen=1024) - index = IntProperty(name="number", - description="Brush number") + mode = StringProperty( + name="mode", + description="Paint mode to set brush for", + maxlen=1024, + ) + index = IntProperty( + name="number", + description="Brush number", + ) _attr_dict = {"sculpt": "use_paint_sculpt", "vertex_paint": "use_paint_vertex", "weight_paint": "use_paint_weight", - "image_paint": "use_paint_image"} + "image_paint": "use_paint_image", + } def execute(self, context): attr = self._attr_dict.get(self.mode) @@ -112,8 +130,11 @@ class WM_OT_context_set_boolean(Operator): bl_options = {'UNDO', 'INTERNAL'} data_path = rna_path_prop - value = BoolProperty(name="Value", - description="Assignment value", default=True) + value = BoolProperty( + name="Value", + description="Assignment value", + default=True, + ) execute = execute_context_assign @@ -125,7 +146,11 @@ class WM_OT_context_set_int(Operator): # same as enum bl_options = {'UNDO', 'INTERNAL'} data_path = rna_path_prop - value = IntProperty(name="Value", description="Assign value", default=0) + value = IntProperty( + name="Value", + description="Assign value", + default=0, + ) relative = rna_relative_prop execute = execute_context_assign @@ -138,10 +163,16 @@ class WM_OT_context_scale_int(Operator): bl_options = {'UNDO', 'INTERNAL'} data_path = rna_path_prop - value = FloatProperty(name="Value", description="Assign value", default=1.0) - always_step = BoolProperty(name="Always Step", - description="Always adjust the value by a minimum of 1 when 'value' is not 1.0.", - default=True) + value = FloatProperty( + name="Value", + description="Assign value", + default=1.0, + ) + always_step = BoolProperty( + name="Always Step", + description="Always adjust the value by a minimum of 1 when 'value' is not 1.0.", + default=True, + ) def execute(self, context): if context_path_validate(context, self.data_path) is Ellipsis: @@ -160,7 +191,8 @@ class WM_OT_context_scale_int(Operator): else: add = "-1" func = "min" - exec("context.%s = %s(round(context.%s * value), context.%s + %s)" % (data_path, func, data_path, data_path, add)) + exec("context.%s = %s(round(context.%s * value), context.%s + %s)" % + (data_path, func, data_path, data_path, add)) else: exec("context.%s *= value" % self.data_path) @@ -174,8 +206,11 @@ class WM_OT_context_set_float(Operator): # same as enum bl_options = {'UNDO', 'INTERNAL'} data_path = rna_path_prop - value = FloatProperty(name="Value", - description="Assignment value", default=0.0) + value = FloatProperty( + name="Value", + description="Assignment value", + default=0.0, + ) relative = rna_relative_prop execute = execute_context_assign @@ -188,8 +223,11 @@ class WM_OT_context_set_string(Operator): # same as enum bl_options = {'UNDO', 'INTERNAL'} data_path = rna_path_prop - value = StringProperty(name="Value", - description="Assign value", maxlen=1024, default="") + value = StringProperty( + name="Value", + description="Assign value", + maxlen=1024, + ) execute = execute_context_assign @@ -201,9 +239,11 @@ class WM_OT_context_set_enum(Operator): bl_options = {'UNDO', 'INTERNAL'} data_path = rna_path_prop - value = StringProperty(name="Value", + value = StringProperty( + name="Value", description="Assignment value (as a string)", - maxlen=1024, default="") + maxlen=1024, + ) execute = execute_context_assign @@ -215,9 +255,11 @@ class WM_OT_context_set_value(Operator): bl_options = {'UNDO', 'INTERNAL'} data_path = rna_path_prop - value = StringProperty(name="Value", + value = StringProperty( + name="Value", description="Assignment value (as a string)", - maxlen=1024, default="") + maxlen=1024, + ) def execute(self, context): if context_path_validate(context, self.data_path) is Ellipsis: @@ -252,21 +294,27 @@ class WM_OT_context_toggle_enum(Operator): bl_options = {'UNDO', 'INTERNAL'} data_path = rna_path_prop - value_1 = StringProperty(name="Value", \ - description="Toggle enum", maxlen=1024, default="") - - value_2 = StringProperty(name="Value", \ - description="Toggle enum", maxlen=1024, default="") + value_1 = StringProperty( + name="Value", + description="Toggle enum", + maxlen=1024, + ) + value_2 = StringProperty( + name="Value", + description="Toggle enum", + maxlen=1024, + ) def execute(self, context): if context_path_validate(context, self.data_path) is Ellipsis: return {'PASS_THROUGH'} - exec("context.%s = ['%s', '%s'][context.%s!='%s']" % \ - (self.data_path, self.value_1,\ - self.value_2, self.data_path, - self.value_2)) + exec("context.%s = ['%s', '%s'][context.%s!='%s']" % + (self.data_path, self.value_1, + self.value_2, self.data_path, + self.value_2, + )) return {'FINISHED'} @@ -426,8 +474,11 @@ class WM_OT_context_set_id(Operator): bl_options = {'UNDO', 'INTERNAL'} data_path = rna_path_prop - value = StringProperty(name="Value", - description="Assign value", maxlen=1024, default="") + value = StringProperty( + name="Value", + description="Assign value", + maxlen=1024, + ) def execute(self, context): value = self.value @@ -454,11 +505,18 @@ class WM_OT_context_set_id(Operator): return {'FINISHED'} -doc_id = StringProperty(name="Doc ID", - description="", maxlen=1024, default="", options={'HIDDEN'}) +doc_id = StringProperty( + name="Doc ID", + description="", + maxlen=1024, + options={'HIDDEN'}, + ) -doc_new = StringProperty(name="Edit Description", - description="", maxlen=1024, default="") +doc_new = StringProperty( + name="Edit Description", + description="", + maxlen=1024, + ) data_path_iter = StringProperty( description="The data path relative to the context, must point to an iterable.") @@ -476,12 +534,13 @@ class WM_OT_context_collection_boolean_set(Operator): data_path_iter = data_path_iter data_path_item = data_path_item - type = EnumProperty(items=( - ('TOGGLE', "Toggle", ""), - ('ENABLE', "Enable", ""), - ('DISABLE', "Disable", ""), - ), - name="Type") + type = EnumProperty( + name="Type", + items=(('TOGGLE', "Toggle", ""), + ('ENABLE', "Enable", ""), + ('DISABLE', "Disable", ""), + ), + ) def execute(self, context): data_path_iter = self.data_path_iter @@ -530,8 +589,14 @@ class WM_OT_context_modal_mouse(Operator): data_path_iter = data_path_iter data_path_item = data_path_item - input_scale = FloatProperty(default=0.01, description="Scale the mouse movement by this value before applying the delta") - invert = BoolProperty(default=False, description="Invert the mouse input") + input_scale = FloatProperty( + description="Scale the mouse movement by this value before applying the delta", + default=0.01, + ) + invert = BoolProperty( + description="Invert the mouse input", + default=False, + ) initial_x = IntProperty(options={'HIDDEN'}) def _values_store(self, context): @@ -613,7 +678,10 @@ class WM_OT_url_open(Operator): bl_idname = "wm.url_open" bl_label = "" - url = StringProperty(name="URL", description="URL to open") + url = StringProperty( + name="URL", + description="URL to open", + ) def execute(self, context): import webbrowser @@ -627,7 +695,11 @@ class WM_OT_path_open(Operator): bl_idname = "wm.path_open" bl_label = "" - filepath = StringProperty(name="File Path", maxlen=1024, subtype='FILE_PATH') + filepath = StringProperty( + name="File Path", + maxlen=1024, + subtype='FILE_PATH', + ) def execute(self, context): import sys @@ -662,9 +734,11 @@ class WM_OT_doc_view(Operator): doc_id = doc_id if bpy.app.version_cycle == "release": - _prefix = "http://www.blender.org/documentation/blender_python_api_%s%s_release" % ("_".join(str(v) for v in bpy.app.version[:2]), bpy.app.version_char) + _prefix = ("http://www.blender.org/documentation/blender_python_api_%s%s_release" % + ("_".join(str(v) for v in bpy.app.version[:2]), bpy.app.version_char)) else: - _prefix = "http://www.blender.org/documentation/blender_python_api_%s" % "_".join(str(v) for v in bpy.app.version) + _prefix = ("http://www.blender.org/documentation/blender_python_api_%s" % + "_".join(str(v) for v in bpy.app.version)) def _nested_class_string(self, class_string): ls = [] @@ -682,8 +756,8 @@ class WM_OT_doc_view(Operator): class_name, class_prop = id_split if hasattr(bpy.types, class_name.upper() + '_OT_' + class_prop): - url = '%s/bpy.ops.%s.html#bpy.ops.%s.%s' % \ - (self._prefix, class_name, class_name, class_prop) + url = ("%s/bpy.ops.%s.html#bpy.ops.%s.%s" % + (self._prefix, class_name, class_name, class_prop)) else: # detect if this is a inherited member and use that name instead @@ -696,8 +770,8 @@ class WM_OT_doc_view(Operator): # It so happens that epydoc nests these, not sphinx # class_name_full = self._nested_class_string(class_name) - url = '%s/bpy.types.%s.html#bpy.types.%s.%s' % \ - (self._prefix, class_name, class_name, class_prop) + url = ("%s/bpy.types.%s.html#bpy.types.%s.%s" % + (self._prefix, class_name, class_name, class_prop)) else: return {'PASS_THROUGH'} @@ -780,17 +854,36 @@ class WM_OT_doc_edit(Operator): return wm.invoke_props_dialog(self, width=600) -rna_path = StringProperty(name="Property Edit", - description="Property data_path edit", maxlen=1024, default="", options={'HIDDEN'}) +rna_path = StringProperty( + name="Property Edit", + description="Property data_path edit", + maxlen=1024, + options={'HIDDEN'}, + ) + +rna_value = StringProperty( + name="Property Value", + description="Property value edit", + maxlen=1024, + ) -rna_value = StringProperty(name="Property Value", - description="Property value edit", maxlen=1024, default="") +rna_property = StringProperty( + name="Property Name", + description="Property name edit", + maxlen=1024, + ) -rna_property = StringProperty(name="Property Name", - description="Property name edit", maxlen=1024, default="") +rna_min = FloatProperty( + name="Min", + default=0.0, + precision=3, + ) -rna_min = FloatProperty(name="Min", default=0.0, precision=3) -rna_max = FloatProperty(name="Max", default=1.0, precision=3) +rna_max = FloatProperty( + name="Max", + default=1.0, + precision=3, + ) class WM_OT_properties_edit(Operator): @@ -804,7 +897,9 @@ class WM_OT_properties_edit(Operator): value = rna_value min = rna_min max = rna_max - description = StringProperty(name="Tip", default="") + description = StringProperty( + name="Tip", + ) def execute(self, context): data_path = self.data_path @@ -908,7 +1003,10 @@ class WM_OT_properties_context_change(Operator): bl_idname = "wm.properties_context_change" bl_label = "" - context = StringProperty(name="Context", maxlen=32) + context = StringProperty( + name="Context", + maxlen=32, + ) def execute(self, context): context.space_data.context = (self.context) @@ -933,7 +1031,10 @@ class WM_OT_keyconfig_activate(Operator): bl_idname = "wm.keyconfig_activate" bl_label = "Activate Keyconfig" - filepath = StringProperty(name="File Path", maxlen=1024) + filepath = StringProperty( + name="File Path", + maxlen=1024, + ) def execute(self, context): bpy.utils.keyconfig_set(self.filepath) @@ -961,7 +1062,10 @@ class WM_OT_appconfig_activate(Operator): bl_idname = "wm.appconfig_activate" bl_label = "Activate Application Configuration" - filepath = StringProperty(name="File Path", maxlen=1024) + filepath = StringProperty( + name="File Path", + maxlen=1024, + ) def execute(self, context): import os -- cgit v1.2.3 From aa4d5ccbed401640065316c59670d23964ab6ad4 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 18 Aug 2011 15:25:18 +0000 Subject: more minor changes to wm.py, get data_path's once at the start of each func and some minor style changes. --- release/scripts/startup/bl_operators/wm.py | 67 ++++++++++++++++-------------- 1 file changed, 36 insertions(+), 31 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index b898d3fbf80..aee36bab688 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -63,11 +63,10 @@ rna_relative_prop = BoolProperty( def context_path_validate(context, data_path): - import sys try: value = eval("context.%s" % data_path) if data_path else Ellipsis - except AttributeError: - if "'NoneType'" in str(sys.exc_info()[1]): + except AttributeError as e: + if str(e).startswith("'NoneType'"): # One of the items in the rna path is None, just ignore this value = Ellipsis else: @@ -78,13 +77,14 @@ def context_path_validate(context, data_path): def execute_context_assign(self, context): - if context_path_validate(context, self.data_path) is Ellipsis: + data_path = self.data_path + if context_path_validate(context, data_path) is Ellipsis: return {'PASS_THROUGH'} if getattr(self, "relative", False): - exec("context.%s+=self.value" % self.data_path) + exec("context.%s += self.value" % data_path) else: - exec("context.%s=self.value" % self.data_path) + exec("context.%s = self.value" % data_path) return {'FINISHED'} @@ -175,11 +175,11 @@ class WM_OT_context_scale_int(Operator): ) def execute(self, context): - if context_path_validate(context, self.data_path) is Ellipsis: + data_path = self.data_path + if context_path_validate(context, data_path) is Ellipsis: return {'PASS_THROUGH'} value = self.value - data_path = self.data_path if value == 1.0: # nothing to do return {'CANCELLED'} @@ -194,7 +194,7 @@ class WM_OT_context_scale_int(Operator): exec("context.%s = %s(round(context.%s * value), context.%s + %s)" % (data_path, func, data_path, data_path, add)) else: - exec("context.%s *= value" % self.data_path) + exec("context.%s *= value" % data_path) return {'FINISHED'} @@ -262,9 +262,10 @@ class WM_OT_context_set_value(Operator): ) def execute(self, context): - if context_path_validate(context, self.data_path) is Ellipsis: + data_path = self.data_path + if context_path_validate(context, data_path) is Ellipsis: return {'PASS_THROUGH'} - exec("context.%s=%s" % (self.data_path, self.value)) + exec("context.%s = %s" % (data_path, self.value)) return {'FINISHED'} @@ -277,12 +278,12 @@ class WM_OT_context_toggle(Operator): data_path = rna_path_prop def execute(self, context): + data_path = self.data_path - if context_path_validate(context, self.data_path) is Ellipsis: + if context_path_validate(context, data_path) is Ellipsis: return {'PASS_THROUGH'} - exec("context.%s=not (context.%s)" % - (self.data_path, self.data_path)) + exec("context.%s = not (context.%s)" % (data_path, data_path)) return {'FINISHED'} @@ -306,13 +307,14 @@ class WM_OT_context_toggle_enum(Operator): ) def execute(self, context): + data_path = self.data_path - if context_path_validate(context, self.data_path) is Ellipsis: + if context_path_validate(context, data_path) is Ellipsis: return {'PASS_THROUGH'} - exec("context.%s = ['%s', '%s'][context.%s!='%s']" % - (self.data_path, self.value_1, - self.value_2, self.data_path, + exec("context.%s = ('%s', '%s')[context.%s != '%s']" % + (data_path, self.value_1, + self.value_2, data_path, self.value_2, )) @@ -340,7 +342,7 @@ class WM_OT_context_cycle_int(Operator): else: value += 1 - exec("context.%s=value" % data_path) + exec("context.%s = value" % data_path) if value != eval("context.%s" % data_path): # relies on rna clamping int's out of the range @@ -349,7 +351,7 @@ class WM_OT_context_cycle_int(Operator): else: value = -1 << 31 - exec("context.%s=value" % data_path) + exec("context.%s = value" % data_path) return {'FINISHED'} @@ -364,15 +366,15 @@ class WM_OT_context_cycle_enum(Operator): reverse = rna_reverse_prop def execute(self, context): - - value = context_path_validate(context, self.data_path) + data_path = self.data_path + value = context_path_validate(context, data_path) if value is Ellipsis: return {'PASS_THROUGH'} orig_value = value # Have to get rna enum values - rna_struct_str, rna_prop_str = self.data_path.rsplit('.', 1) + rna_struct_str, rna_prop_str = data_path.rsplit('.', 1) i = rna_prop_str.find('[') # just incse we get "context.foo.bar[0]" @@ -402,7 +404,7 @@ class WM_OT_context_cycle_enum(Operator): advance_enum = enums[orig_index + 1] # set the new value - exec("context.%s=advance_enum" % self.data_path) + exec("context.%s = advance_enum" % data_path) return {'FINISHED'} @@ -429,7 +431,7 @@ class WM_OT_context_cycle_array(Operator): array.append(array.pop(0)) return array - exec("context.%s=cycle(context.%s[:])" % (data_path, data_path)) + exec("context.%s = cycle(context.%s[:])" % (data_path, data_path)) return {'FINISHED'} @@ -500,7 +502,7 @@ class WM_OT_context_set_id(Operator): if id_iter: value_id = getattr(bpy.data, id_iter).get(value) - exec("context.%s=value_id" % data_path) + exec("context.%s = value_id" % data_path) return {'FINISHED'} @@ -952,14 +954,15 @@ class WM_OT_properties_edit(Operator): return {'FINISHED'} def invoke(self, context, event): + data_path = self.data_path - if not self.data_path: + if not data_path: self.report({'ERROR'}, "Data path not set") return {'CANCELLED'} self._last_prop = [self.property] - item = eval("context.%s" % self.data_path) + item = eval("context.%s" % data_path) # setup defaults prop_ui = rna_idprop_ui_prop_get(item, self.property, False) # dont create @@ -980,7 +983,8 @@ class WM_OT_properties_add(Operator): data_path = rna_path def execute(self, context): - item = eval("context.%s" % self.data_path) + data_path = self.data_path + item = eval("context.%s" % data_path) def unique_name(names): prop = 'prop' @@ -1009,7 +1013,7 @@ class WM_OT_properties_context_change(Operator): ) def execute(self, context): - context.space_data.context = (self.context) + context.space_data.context = self.context return {'FINISHED'} @@ -1022,7 +1026,8 @@ class WM_OT_properties_remove(Operator): property = rna_property def execute(self, context): - item = eval("context.%s" % self.data_path) + data_path = self.data_path + item = eval("context.%s" % data_path) del item[self.property] return {'FINISHED'} -- cgit v1.2.3 From feb83181437cd36b283ae6551f10045d1fdbedd5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 18 Aug 2011 16:01:11 +0000 Subject: fix for undo issues with generic, multi-purpose WM_OT_context* operators, operators now check if they modify certain ID data (not screne, wm, brush or scene) and only do undo in those cass. - Zkey to switch shading was pushing undo's. - Wkey to interactively edit camera, lamp settings wasnt doing an undo push when it should. - Toggling settings (such as bone boolean options) now skips an undo push if there are no items selected. --- release/scripts/startup/bl_operators/wm.py | 79 +++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 13 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index aee36bab688..885d8cf2aed 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -76,6 +76,54 @@ def context_path_validate(context, data_path): return value +def operator_value_is_undo(value): + if value in {None, Ellipsis}: + return False + + # typical properties or objects + id_data = getattr(value, "id_data", Ellipsis) + + if id_data is None: + return False + elif id_data is Ellipsis: + # handle mathutils types + id_data = getattr(getattr(value, "owner", None), "id_data", None) + + if id_data is None: + return False + + # return True if its a non window ID type + return (isinstance(id_data, bpy.types.ID) and + (not isinstance(id_data, (bpy.types.WindowManager, + bpy.types.Screen, + bpy.types.Scene, + bpy.types.Brush, + )))) + + +def operator_path_is_undo(context, data_path): + # note that if we have data paths that use strings this could fail + # luckily we dont do this! + # + # When we cant find the data owner assume no undo is needed. + data_path_head, data_path_sep, data_path_tail = data_path.rpartition(".") + + if not data_path_head: + return False + + value = context_path_validate(context, data_path_head) + + return operator_value_is_undo(value) + + +def operator_path_undo_return(context, data_path): + return {'FINISHED'} if operator_path_is_undo(context, data_path) else {'CANCELLED'} + + +def operator_value_undo_return(value): + return {'FINISHED'} if operator_value_is_undo(value) else {'CANCELLED'} + + def execute_context_assign(self, context): data_path = self.data_path if context_path_validate(context, data_path) is Ellipsis: @@ -86,7 +134,7 @@ def execute_context_assign(self, context): else: exec("context.%s = self.value" % data_path) - return {'FINISHED'} + return operator_path_undo_return(context, data_path) class BRUSH_OT_active_index_set(Operator): @@ -196,7 +244,7 @@ class WM_OT_context_scale_int(Operator): else: exec("context.%s *= value" % data_path) - return {'FINISHED'} + return operator_path_undo_return(context, data_path) class WM_OT_context_set_float(Operator): # same as enum @@ -266,7 +314,7 @@ class WM_OT_context_set_value(Operator): if context_path_validate(context, data_path) is Ellipsis: return {'PASS_THROUGH'} exec("context.%s = %s" % (data_path, self.value)) - return {'FINISHED'} + return operator_path_undo_return(context, data_path) class WM_OT_context_toggle(Operator): @@ -285,7 +333,7 @@ class WM_OT_context_toggle(Operator): exec("context.%s = not (context.%s)" % (data_path, data_path)) - return {'FINISHED'} + return operator_path_undo_return(context, data_path) class WM_OT_context_toggle_enum(Operator): @@ -318,7 +366,7 @@ class WM_OT_context_toggle_enum(Operator): self.value_2, )) - return {'FINISHED'} + return operator_path_undo_return(context, data_path) class WM_OT_context_cycle_int(Operator): @@ -353,7 +401,7 @@ class WM_OT_context_cycle_int(Operator): exec("context.%s = value" % data_path) - return {'FINISHED'} + return operator_path_undo_return(context, data_path) class WM_OT_context_cycle_enum(Operator): @@ -405,7 +453,7 @@ class WM_OT_context_cycle_enum(Operator): # set the new value exec("context.%s = advance_enum" % data_path) - return {'FINISHED'} + return operator_path_undo_return(context, data_path) class WM_OT_context_cycle_array(Operator): @@ -433,7 +481,7 @@ class WM_OT_context_cycle_array(Operator): exec("context.%s = cycle(context.%s[:])" % (data_path, data_path)) - return {'FINISHED'} + return operator_path_undo_return(context, data_path) class WM_MT_context_menu_enum(Menu): @@ -504,7 +552,7 @@ class WM_OT_context_set_id(Operator): value_id = getattr(bpy.data, id_iter).get(value) exec("context.%s = value_id" % data_path) - return {'FINISHED'} + return operator_path_undo_return(context, data_path) doc_id = StringProperty( @@ -568,6 +616,10 @@ class WM_OT_context_collection_boolean_set(Operator): items_ok.append(item) + # avoid undo push when nothing to do + if not items_ok: + return {'CANCELLED'} + if self.type == 'ENABLE': is_set = True elif self.type == 'DISABLE': @@ -579,14 +631,14 @@ class WM_OT_context_collection_boolean_set(Operator): for item in items_ok: exec(exec_str) - return {'FINISHED'} + return operator_value_undo_return(item) class WM_OT_context_modal_mouse(Operator): '''Adjust arbitrary values with mouse input''' bl_idname = "wm.context_modal_mouse" bl_label = "Context Modal Mouse" - bl_options = {'GRAB_POINTER', 'BLOCKING', 'INTERNAL'} + bl_options = {'GRAB_POINTER', 'BLOCKING', 'UNDO', 'INTERNAL'} data_path_iter = data_path_iter data_path_item = data_path_item @@ -651,12 +703,13 @@ class WM_OT_context_modal_mouse(Operator): self._values_delta(delta) elif 'LEFTMOUSE' == event_type: + item = next(iter(self._values.keys())) self._values_clear() - return {'FINISHED'} + return operator_value_undo_return(item) elif event_type in {'RIGHTMOUSE', 'ESC'}: self._values_restore() - return {'FINISHED'} + return {'CANCELLED'} return {'RUNNING_MODAL'} -- cgit v1.2.3 From 90d19ad883b60511bfdbf9eba9fc9e46c3d69f51 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 19 Aug 2011 19:25:20 +0000 Subject: py style change only - make property definitions consistent --- .../scripts/startup/bl_operators/add_mesh_torus.py | 66 ++++++++---- release/scripts/startup/bl_operators/mesh.py | 10 +- release/scripts/startup/bl_operators/object.py | 8 +- .../scripts/startup/bl_operators/object_align.py | 55 +++++----- .../startup/bl_operators/object_quick_effects.py | 111 ++++++++++++--------- .../bl_operators/object_randomize_transform.py | 9 +- release/scripts/startup/bl_operators/sequencer.py | 8 +- .../startup/bl_operators/uvcalc_lightmap.py | 1 - .../startup/bl_operators/uvcalc_smart_project.py | 23 +++-- .../startup/bl_operators/vertexpaint_dirt.py | 34 ++++++- release/scripts/startup/bl_operators/wm.py | 2 - release/scripts/startup/bl_ui/__init__.py | 5 +- release/scripts/startup/bl_ui/space_console.py | 6 +- release/scripts/startup/bl_ui/space_userpref.py | 46 +++++++-- .../scripts/startup/bl_ui/space_userpref_keymap.py | 70 ++++++++++--- release/scripts/templates/addon_add_object.py | 10 +- release/scripts/templates/operator_export.py | 26 +++-- release/scripts/templates/operator_mesh_add.py | 41 +++++--- release/scripts/templates/operator_modal_view3d.py | 5 +- 19 files changed, 364 insertions(+), 172 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py index 1c4518c4feb..056b3478c2b 100644 --- a/release/scripts/startup/bl_operators/add_mesh_torus.py +++ b/release/scripts/startup/bl_operators/add_mesh_torus.py @@ -88,36 +88,62 @@ class AddTorus(Operator): bl_label = "Add Torus" bl_options = {'REGISTER', 'UNDO'} - major_radius = FloatProperty(name="Major Radius", + major_radius = FloatProperty( + name="Major Radius", description=("Radius from the origin to the " "center of the cross sections"), - default=1.0, min=0.01, max=100.0) - minor_radius = FloatProperty(name="Minor Radius", + min=0.01, max=100.0, + default=1.0, + ) + minor_radius = FloatProperty( + name="Minor Radius", description="Radius of the torus' cross section", - default=0.25, min=0.01, max=100.0) - major_segments = IntProperty(name="Major Segments", + min=0.01, max=100.0, + default=0.25, + ) + major_segments = IntProperty( + name="Major Segments", description="Number of segments for the main ring of the torus", - default=48, min=3, max=256) - minor_segments = IntProperty(name="Minor Segments", + min=3, max=256, + default=48, + ) + minor_segments = IntProperty( + name="Minor Segments", description="Number of segments for the minor ring of the torus", - default=12, min=3, max=256) - use_abso = BoolProperty(name="Use Int+Ext Controls", + min=3, max=256, + default=12, + ) + use_abso = BoolProperty( + name="Use Int+Ext Controls", description="Use the Int / Ext controls for torus dimensions", - default=False) - abso_major_rad = FloatProperty(name="Exterior Radius", + default=False, + ) + abso_major_rad = FloatProperty( + name="Exterior Radius", description="Total Exterior Radius of the torus", - default=1.0, min=0.01, max=100.0) - abso_minor_rad = FloatProperty(name="Inside Radius", + min=0.01, max=100.0, + default=1.0, + ) + abso_minor_rad = FloatProperty( + name="Inside Radius", description="Total Interior Radius of the torus", - default=0.5, min=0.01, max=100.0) + min=0.01, max=100.0, + default=0.5, + ) # generic transform props - view_align = BoolProperty(name="Align to View", - default=False) - location = FloatVectorProperty(name="Location", - subtype='TRANSLATION') - rotation = FloatVectorProperty(name="Rotation", - subtype='EULER') + view_align = BoolProperty( + name="Align to View", + default=False, + ) + location = FloatVectorProperty( + name="Location", + subtype='TRANSLATION', + ) + rotation = FloatVectorProperty( + name="Rotation", + subtype='EULER', + ) def execute(self, context): diff --git a/release/scripts/startup/bl_operators/mesh.py b/release/scripts/startup/bl_operators/mesh.py index 4114381f3dc..5f6583754e9 100644 --- a/release/scripts/startup/bl_operators/mesh.py +++ b/release/scripts/startup/bl_operators/mesh.py @@ -74,11 +74,11 @@ class MeshMirrorUV(Operator): bl_label = "Copy Mirrored UV coords" bl_options = {'REGISTER', 'UNDO'} - direction = EnumProperty(items=( - ('POSITIVE', "Positive", ""), - ('NEGATIVE', "Negative", "")), - name="Axis Direction", - description="") + direction = EnumProperty( + name="Axis Direction", + items=(('POSITIVE', "Positive", ""), + ('NEGATIVE', "Negative", "")), + ) @classmethod def poll(cls, context): diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py index 79f57990f37..d26ec53e4e3 100644 --- a/release/scripts/startup/bl_operators/object.py +++ b/release/scripts/startup/bl_operators/object.py @@ -195,8 +195,12 @@ class SubdivisionSet(Operator): bl_label = "Subdivision Set" bl_options = {'REGISTER', 'UNDO'} - level = IntProperty(name="Level", - default=1, min=-100, max=100, soft_min=-6, soft_max=6) + level = IntProperty( + name="Level", + min=-100, max=100, + soft_min=-6, soft_max=6, + default=1, + ) relative = BoolProperty( name="Relative", diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py index d4a3d826f2f..50e9bfb5b98 100644 --- a/release/scripts/startup/bl_operators/object_align.py +++ b/release/scripts/startup/bl_operators/object_align.py @@ -351,33 +351,34 @@ class AlignObjects(Operator): description=("Enables high quality calculation of the " "bounding box for perfect results on complex " "shape meshes with rotation/scale (Slow)"), - default=True) - - align_mode = EnumProperty(items=( - ('OPT_1', "Negative Sides", ""), - ('OPT_2', "Centers", ""), - ('OPT_3', "Positive Sides", "")), - name="Align Mode:", - description="", - default='OPT_2') - - relative_to = EnumProperty(items=( - ('OPT_1', "Scene Origin", ""), - ('OPT_2', "3D Cursor", ""), - ('OPT_3', "Selection", ""), - ('OPT_4', "Active", "")), - name="Relative To:", - description="", - default='OPT_4') - - align_axis = EnumProperty(items=( - ('X', "X", ""), - ('Y', "Y", ""), - ('Z', "Z", ""), - ), - name="Align", - description="Align to axis", - options={'ENUM_FLAG'}) + default=True, + ) + align_mode = EnumProperty( + name="Align Mode:", + items=(('OPT_1', "Negative Sides", ""), + ('OPT_2', "Centers", ""), + ('OPT_3', "Positive Sides", ""), + ), + default='OPT_2', + ) + relative_to = EnumProperty( + name="Relative To:", + items=(('OPT_1', "Scene Origin", ""), + ('OPT_2', "3D Cursor", ""), + ('OPT_3', "Selection", ""), + ('OPT_4', "Active", ""), + ), + default='OPT_4', + ) + align_axis = EnumProperty( + name="Align", + description="Align to axis", + items=(('X', "X", ""), + ('Y', "Y", ""), + ('Z', "Z", ""), + ), + options={'ENUM_FLAG'}, + ) @classmethod def poll(cls, context): diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py index cd206da3a8e..48b547980d4 100644 --- a/release/scripts/startup/bl_operators/object_quick_effects.py +++ b/release/scripts/startup/bl_operators/object_quick_effects.py @@ -51,19 +51,25 @@ class QuickFur(Operator): bl_label = "Quick Fur" bl_options = {'REGISTER', 'UNDO'} - density = EnumProperty(items=( - ('LIGHT', "Light", ""), - ('MEDIUM', "Medium", ""), - ('HEAVY', "Heavy", "")), - name="Fur Density", - description="", - default='MEDIUM') - - view_percentage = IntProperty(name="View %", - default=10, min=1, max=100, soft_min=1, soft_max=100) - - length = FloatProperty(name="Length", - default=0.1, min=0.001, max=100, soft_min=0.01, soft_max=10) + 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 = bpy.context.copy() @@ -110,31 +116,50 @@ class QuickExplode(Operator): bl_label = "Quick Explode" bl_options = {'REGISTER', 'UNDO'} - style = EnumProperty(items=( - ('EXPLODE', "Explode", ""), - ('BLEND', "Blend", "")), - name="Explode Style", - description="", - default='EXPLODE') - - amount = IntProperty(name="Amount of pieces", - default=100, min=2, max=10000, soft_min=2, soft_max=10000) - - frame_duration = IntProperty(name="Duration", - default=50, min=1, max=300000, soft_min=1, soft_max=10000) - - frame_start = IntProperty(name="Start Frame", - default=1, min=1, max=300000, soft_min=1, soft_max=10000) + 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_end = IntProperty(name="End Frame", - default=10, min=1, max=300000, soft_min=1, soft_max=10000) + 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", - default=1, min=0, max=300000, soft_min=0, soft_max=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) + fade = BoolProperty( + name="Fade", + description="Fade the pieces over time.", + default=True, + ) def execute(self, context): fake_context = bpy.context.copy() @@ -272,12 +297,11 @@ class QuickSmoke(Operator): bl_options = {'REGISTER', 'UNDO'} style = EnumProperty( + name="Smoke Style", items=(('STREAM', "Stream", ""), ('PUFF', "Puff", ""), ('FIRE', "Fire", ""), ), - name="Smoke Style", - description="", default='STREAM', ) @@ -390,19 +414,16 @@ class QuickFluid(Operator): bl_options = {'REGISTER', 'UNDO'} style = EnumProperty( + name="Fluid Style", items=(('INFLOW', "Inflow", ""), - ('BASIC', "Basic", ""), - ), - name="Fluid Style", - description="", - default='BASIC', - ) + ('BASIC', "Basic", "")), + default='BASIC', + ) initial_velocity = FloatVectorProperty( name="Initial Velocity", description="Initial velocity of the fluid", + min=-100.0, max=100.0, default=(0.0, 0.0, 0.0), - min=-100.0, - max=100.0, subtype='VELOCITY', ) show_flows = BoolProperty( diff --git a/release/scripts/startup/bl_operators/object_randomize_transform.py b/release/scripts/startup/bl_operators/object_randomize_transform.py index f65e3d27d83..7aea18487f3 100644 --- a/release/scripts/startup/bl_operators/object_randomize_transform.py +++ b/release/scripts/startup/bl_operators/object_randomize_transform.py @@ -145,9 +145,12 @@ class RandomizeLocRotSize(Operator): default=False, ) - '''scale_min = FloatProperty(name="Minimun Scale Factor", - description="Lowest scale percentage possible", - default=0.15, min=-1.0, max=1.0, precision=3)''' + '''scale_min = FloatProperty( + name="Minimun Scale Factor", + description="Lowest scale percentage possible", + min=-1.0, max=1.0, precision=3, + default=0.15, + )''' scale = FloatVectorProperty( name="Scale", diff --git a/release/scripts/startup/bl_operators/sequencer.py b/release/scripts/startup/bl_operators/sequencer.py index d2f85c8d7c7..856e182279a 100644 --- a/release/scripts/startup/bl_operators/sequencer.py +++ b/release/scripts/startup/bl_operators/sequencer.py @@ -82,8 +82,12 @@ class SequencerCutMulticam(Operator): bl_label = "Cut multicam" bl_options = {'REGISTER', 'UNDO'} - camera = IntProperty(name="Camera", - default=1, min=1, max=32, soft_min=1, soft_max=32) + camera = IntProperty( + name="Camera", + min=1, max=32, + soft_min=1, soft_max=32, + default=1, + ) @classmethod def poll(cls, context): diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py index 6b1c6e1be98..060fe400045 100644 --- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py +++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py @@ -552,7 +552,6 @@ class LightMapPack(Operator): PREF_CONTEXT = bpy.props.EnumProperty( name="Selection", - description="", items=(("SEL_FACES", "Selected Faces", "Space all UVs evently"), ("ALL_FACES", "All Faces", "Average space UVs edge length of each loop"), ("ALL_OBJECTS", "Selected Mesh Object", "Average space UVs edge length of each loop") diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py index 8afd6c104e0..78b68418322 100644 --- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py +++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py @@ -1110,17 +1110,24 @@ class SmartProject(Operator): bl_label = "Smart UV Project" bl_options = {'REGISTER', 'UNDO'} - angle_limit = FloatProperty(name="Angle Limit", + angle_limit = FloatProperty( + name="Angle Limit", description="lower for more projection groups, higher for less distortion", - default=66.0, min=1.0, max=89.0) - - island_margin = FloatProperty(name="Island Margin", + min=1.0, max=89.0, + default=66.0, + ) + island_margin = FloatProperty( + name="Island Margin", description="Margin to reduce bleed from adjacent islands", - default=0.0, min=0.0, max=1.0) - - user_area_weight = FloatProperty(name="Area Weight", + min=0.0, max=1.0, + default=0.0, + ) + user_area_weight = FloatProperty( + name="Area Weight", description="Weight projections vector by faces with larger areas", - default=0.0, min=0.0, max=1.0) + min=0.0, max=1.0, + default=0.0, + ) @classmethod def poll(cls, context): diff --git a/release/scripts/startup/bl_operators/vertexpaint_dirt.py b/release/scripts/startup/bl_operators/vertexpaint_dirt.py index facde82f812..4c78adb7161 100644 --- a/release/scripts/startup/bl_operators/vertexpaint_dirt.py +++ b/release/scripts/startup/bl_operators/vertexpaint_dirt.py @@ -151,11 +151,35 @@ class VertexPaintDirt(Operator): bl_label = "Dirty Vertex Colors" bl_options = {'REGISTER', 'UNDO'} - blur_strength = FloatProperty(name="Blur Strength", description="Blur strength per iteration", default=1.0, min=0.01, max=1.0) - blur_iterations = IntProperty(name="Blur Iterations", description="Number times to blur the colors. (higher blurs more)", default=1, min=0, max=40) - clean_angle = FloatProperty(name="Highlight Angle", description="Less then 90 limits the angle used in the tonal range", default=180.0, min=0.0, max=180.0) - dirt_angle = FloatProperty(name="Dirt Angle", description="Less then 90 limits the angle used in the tonal range", default=0.0, min=0.0, max=180.0) - dirt_only = BoolProperty(name="Dirt Only", description="Dont calculate cleans for convex areas", default=False) + blur_strength = FloatProperty( + name="Blur Strength", + description="Blur strength per iteration", + min=0.01, max=1.0, + default=1.0, + ) + blur_iterations = IntProperty( + name="Blur Iterations", + description="Number times to blur the colors. (higher blurs more)", + min=0, max=40, + default=1, + ) + clean_angle = FloatProperty( + name="Highlight Angle", + description="Less then 90 limits the angle used in the tonal range", + min=0.0, max=180.0, + default=180.0, + ) + dirt_angle = FloatProperty( + name="Dirt Angle", + description="Less then 90 limits the angle used in the tonal range", + min=0.0, max=180.0, + default=0.0, + ) + dirt_only = BoolProperty( + name="Dirt Only", + description="Dont calculate cleans for convex areas", + default=False, + ) def execute(self, context): import time diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 885d8cf2aed..74f125e0ad3 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -557,14 +557,12 @@ class WM_OT_context_set_id(Operator): doc_id = StringProperty( name="Doc ID", - description="", maxlen=1024, options={'HIDDEN'}, ) doc_new = StringProperty( name="Edit Description", - description="", maxlen=1024, ) diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py index bf63c6071b9..e1a23143bc0 100644 --- a/release/scripts/startup/bl_ui/__init__.py +++ b/release/scripts/startup/bl_ui/__init__.py @@ -102,7 +102,10 @@ def register(): items.extend([(cat, cat, "") for cat in sorted(items_unique)]) return items - WindowManager.addon_search = StringProperty(name="Search", description="Search within the selected filter") + WindowManager.addon_search = StringProperty( + name="Search", + description="Search within the selected filter", + ) WindowManager.addon_filter = EnumProperty( items=addon_filter_items, name="Category", diff --git a/release/scripts/startup/bl_ui/space_console.py b/release/scripts/startup/bl_ui/space_console.py index d457a66def8..b517e0d86fb 100644 --- a/release/scripts/startup/bl_ui/space_console.py +++ b/release/scripts/startup/bl_ui/space_console.py @@ -141,7 +141,11 @@ class ConsoleLanguage(Operator): '''Set the current language for this console''' bl_idname = "console.language" bl_label = "Console Language" - language = StringProperty(name="Language", maxlen=32, default="") + + language = StringProperty( + name="Language", + maxlen=32, + ) def execute(self, context): sc = context.space_data diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 148338368fe..13edc3471d2 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -1106,7 +1106,10 @@ class WM_OT_addon_disable(Operator): bl_idname = "wm.addon_disable" bl_label = "Disable Add-On" - module = StringProperty(name="Module", description="Module name of the addon to disable") + module = StringProperty( + name="Module", + description="Module name of the addon to disable", + ) def execute(self, context): addon_utils.disable(self.module) @@ -1118,16 +1121,35 @@ class WM_OT_addon_install(Operator): bl_idname = "wm.addon_install" bl_label = "Install Add-On..." - overwrite = BoolProperty(name="Overwrite", description="Remove existing addons with the same ID", default=True) + overwrite = BoolProperty( + name="Overwrite", + description="Remove existing addons with the same ID", + default=True, + ) target = EnumProperty( name="Target Path", items=(('DEFAULT', "Default", ""), - ('PREFS', "User Prefs", ""))) + ('PREFS', "User Prefs", "")), + ) - filepath = StringProperty(name="File Path", description="File path to write file to") - filter_folder = BoolProperty(name="Filter folders", description="", default=True, options={'HIDDEN'}) - filter_python = BoolProperty(name="Filter python", description="", default=True, options={'HIDDEN'}) - filter_glob = StringProperty(default="*.py;*.zip", options={'HIDDEN'}) + filepath = StringProperty( + name="File Path", + description="File path to write file to", + ) + filter_folder = BoolProperty( + name="Filter folders", + default=True, + options={'HIDDEN'}, + ) + filter_python = BoolProperty( + name="Filter python", + default=True, + options={'HIDDEN'}, + ) + filter_glob = StringProperty( + default="*.py;*.zip", + options={'HIDDEN'}, + ) @staticmethod def _module_remove(path_addons, module): @@ -1264,7 +1286,10 @@ class WM_OT_addon_remove(Operator): bl_idname = "wm.addon_remove" bl_label = "Remove Add-On" - module = StringProperty(name="Module", description="Module name of the addon to remove") + module = StringProperty( + name="Module", + description="Module name of the addon to remove", + ) @staticmethod def path_from_addon(module): @@ -1312,7 +1337,10 @@ class WM_OT_addon_expand(Operator): bl_idname = "wm.addon_expand" bl_label = "" - module = StringProperty(name="Module", description="Module name of the addon to expand") + module = StringProperty( + name="Module", + description="Module name of the addon to expand", + ) def execute(self, context): module_name = self.module diff --git a/release/scripts/startup/bl_ui/space_userpref_keymap.py b/release/scripts/startup/bl_ui/space_userpref_keymap.py index 6a81ff5830e..9ed1591cbf3 100644 --- a/release/scripts/startup/bl_ui/space_userpref_keymap.py +++ b/release/scripts/startup/bl_ui/space_userpref_keymap.py @@ -533,12 +533,31 @@ class WM_OT_keyconfig_import(Operator): bl_idname = "wm.keyconfig_import" bl_label = "Import Key Configuration..." - filepath = StringProperty(name="File Path", description="Filepath to write file to", default="keymap.py") - filter_folder = BoolProperty(name="Filter folders", description="", default=True, options={'HIDDEN'}) - filter_text = BoolProperty(name="Filter text", description="", default=True, options={'HIDDEN'}) - filter_python = BoolProperty(name="Filter python", description="", default=True, options={'HIDDEN'}) - - keep_original = BoolProperty(name="Keep original", description="Keep original file after copying to configuration folder", default=True) + filepath = StringProperty( + name="File Path", + description="Filepath to write file to", + default="keymap.py", + ) + filter_folder = BoolProperty( + name="Filter folders", + default=True, + options={'HIDDEN'}, + ) + filter_text = BoolProperty( + name="Filter text", + default=True, + options={'HIDDEN'}, + ) + filter_python = BoolProperty( + name="Filter python", + default=True, + options={'HIDDEN'}, + ) + keep_original = BoolProperty( + name="Keep original", + description="Keep original file after copying to configuration folder", + default=True, + ) def execute(self, context): from os.path import basename @@ -580,10 +599,26 @@ class WM_OT_keyconfig_export(Operator): bl_idname = "wm.keyconfig_export" bl_label = "Export Key Configuration..." - filepath = StringProperty(name="File Path", description="Filepath to write file to", default="keymap.py") - filter_folder = BoolProperty(name="Filter folders", description="", default=True, options={'HIDDEN'}) - filter_text = BoolProperty(name="Filter text", description="", default=True, options={'HIDDEN'}) - filter_python = BoolProperty(name="Filter python", description="", default=True, options={'HIDDEN'}) + filepath = StringProperty( + name="File Path", + description="Filepath to write file to", + default="keymap.py", + ) + filter_folder = BoolProperty( + name="Filter folders", + default=True, + options={'HIDDEN'}, + ) + filter_text = BoolProperty( + name="Filter text", + default=True, + options={'HIDDEN'}, + ) + filter_python = BoolProperty( + name="Filter python", + default=True, + options={'HIDDEN'}, + ) def execute(self, context): if not self.filepath: @@ -673,7 +708,10 @@ class WM_OT_keymap_restore(Operator): bl_idname = "wm.keymap_restore" bl_label = "Restore Key Map(s)" - all = BoolProperty(name="All Keymaps", description="Restore all keymaps to default") + all = BoolProperty( + name="All Keymaps", + description="Restore all keymaps to default", + ) def execute(self, context): wm = context.window_manager @@ -693,7 +731,10 @@ class WM_OT_keyitem_restore(Operator): bl_idname = "wm.keyitem_restore" bl_label = "Restore Key Map Item" - item_id = IntProperty(name="Item Identifier", description="Identifier of the item to remove") + item_id = IntProperty( + name="Item Identifier", + description="Identifier of the item to remove", + ) @classmethod def poll(cls, context): @@ -737,7 +778,10 @@ class WM_OT_keyitem_remove(Operator): bl_idname = "wm.keyitem_remove" bl_label = "Remove Key Map Item" - item_id = IntProperty(name="Item Identifier", description="Identifier of the item to remove") + item_id = IntProperty( + name="Item Identifier", + description="Identifier of the item to remove", + ) @classmethod def poll(cls, context): diff --git a/release/scripts/templates/addon_add_object.py b/release/scripts/templates/addon_add_object.py index 98517fd97a0..833ac600995 100644 --- a/release/scripts/templates/addon_add_object.py +++ b/release/scripts/templates/addon_add_object.py @@ -45,10 +45,12 @@ class OBJECT_OT_add_object(bpy.types.Operator, AddObjectHelper): bl_description = "Create a new Mesh Object" bl_options = {'REGISTER', 'UNDO'} - scale = FloatVectorProperty(name='scale', - default=(1.0, 1.0, 1.0), - subtype='TRANSLATION', - description='scaling') + scale = FloatVectorProperty( + name='scale', + default=(1.0, 1.0, 1.0), + subtype='TRANSLATION', + description='scaling', + ) def execute(self, context): diff --git a/release/scripts/templates/operator_export.py b/release/scripts/templates/operator_export.py index 4cf943a53b7..aeda4ce36fb 100644 --- a/release/scripts/templates/operator_export.py +++ b/release/scripts/templates/operator_export.py @@ -24,18 +24,26 @@ class ExportSomeData(bpy.types.Operator, ExportHelper): # ExportHelper mixin class uses this filename_ext = ".txt" - filter_glob = StringProperty(default="*.txt", options={'HIDDEN'}) + filter_glob = StringProperty( + default="*.txt", + options={'HIDDEN'}, + ) # List of operator properties, the attributes will be assigned # to the class instance from the operator settings before calling. - use_setting = BoolProperty(name="Example Boolean", description="Example Tooltip", default=True) - - type = EnumProperty(items=(('OPT_A', "First Option", "Description one"), - ('OPT_B', "Second Option", "Description two."), - ), - name="Example Enum", - description="Choose between two items", - default='OPT_A') + use_setting = BoolProperty( + name="Example Boolean", + description="Example Tooltip", + default=True, + ) + + type = EnumProperty( + name="Example Enum", + description="Choose between two items", + items=(('OPT_A', "First Option", "Description one"), + ('OPT_B', "Second Option", "Description two.")), + default='OPT_A', + ) @classmethod def poll(cls, context): diff --git a/release/scripts/templates/operator_mesh_add.py b/release/scripts/templates/operator_mesh_add.py index 10d23a6712d..d89b7e82f77 100644 --- a/release/scripts/templates/operator_mesh_add.py +++ b/release/scripts/templates/operator_mesh_add.py @@ -43,25 +43,38 @@ class AddBox(bpy.types.Operator): bl_label = "Add Box" bl_options = {'REGISTER', 'UNDO'} - width = FloatProperty(name="Width", + width = FloatProperty( + name="Width", description="Box Width", - default=1.0, min=0.01, max=100.0) - - height = FloatProperty(name="Height", + min=0.01, max=100.0, + default=1.0, + ) + height = FloatProperty( + name="Height", description="Box Height", - default=1.0, min=0.01, max=100.0) - - depth = FloatProperty(name="Depth", + min=0.01, max=100.0, + default=1.0, + ) + depth = FloatProperty( + name="Depth", description="Box Depth", - default=1.0, min=0.01, max=100.0) + min=0.01, max=100.0, + default=1.0, + ) # generic transform props - view_align = BoolProperty(name="Align to View", - default=False) - location = FloatVectorProperty(name="Location", - subtype='TRANSLATION') - rotation = FloatVectorProperty(name="Rotation", - subtype='EULER') + view_align = BoolProperty( + name="Align to View", + default=False, + ) + location = FloatVectorProperty( + name="Location", + subtype='TRANSLATION', + ) + rotation = FloatVectorProperty( + name="Rotation", + subtype='EULER', + ) def execute(self, context): diff --git a/release/scripts/templates/operator_modal_view3d.py b/release/scripts/templates/operator_modal_view3d.py index 925449835ca..263bf72f129 100644 --- a/release/scripts/templates/operator_modal_view3d.py +++ b/release/scripts/templates/operator_modal_view3d.py @@ -8,7 +8,10 @@ class ViewOperator(bpy.types.Operator): bl_idname = "view3d.modal_operator" bl_label = "Simple View Operator" - offset = FloatVectorProperty(name="Offset", size=3) + offset = FloatVectorProperty( + name="Offset", + size=3, + ) def execute(self, context): v3d = context.space_data -- cgit v1.2.3 From 06ae5e48258dacc5598b23286d46891be32a08e5 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 22 Aug 2011 02:14:39 +0000 Subject: Reshuffling DopeSheet filter icons so that they appear more obviously related to each other --- release/scripts/startup/bl_ui/space_dopesheet.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index cab58a3aadb..74ae427c5cf 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -35,7 +35,7 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False): row.prop(dopesheet, "show_hidden", text="") if is_nla: - row.prop(dopesheet, "show_missing_nla", text="") + row.prop(dopesheet, "show_missing_nla", text="") if not genericFiltersOnly: if bpy.data.groups: @@ -50,21 +50,16 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False): if dopesheet.show_only_matching_fcurves: row.prop(dopesheet, "filter_fcurve_name", text="") - row = layout.row() - row.prop(dopesheet, "show_datablock_filters", text="Filters", icon='DISCLOSURE_TRI_RIGHT') + row = layout.row(align=True) + row.prop(dopesheet, "show_datablock_filters", text="Filters") if (not genericFiltersOnly) and (dopesheet.show_datablock_filters): - # TODO: put a box around these? - subrow = row.row() - - row = subrow.row(align=True) - row.prop(dopesheet, "show_transforms", text="") - - row = subrow.row(align=True) row.prop(dopesheet, "show_scenes", text="") row.prop(dopesheet, "show_worlds", text="") row.prop(dopesheet, "show_nodes", text="") + row.prop(dopesheet, "show_transforms", text="") + if bpy.data.meshes: row.prop(dopesheet, "show_meshes", text="") if bpy.data.shape_keys: -- cgit v1.2.3 From a594196dc0cf0482aab7d16b4cfee1a7d3b8707d Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 22 Aug 2011 02:30:43 +0000 Subject: Bugfix: "Filters" toggle was being shown in Action Editor too, where it was irrelevant --- release/scripts/startup/bl_ui/space_dopesheet.py | 69 ++++++++++++------------ 1 file changed, 35 insertions(+), 34 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 74ae427c5cf..a2a51f9587f 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -50,40 +50,41 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False): if dopesheet.show_only_matching_fcurves: row.prop(dopesheet, "filter_fcurve_name", text="") - row = layout.row(align=True) - row.prop(dopesheet, "show_datablock_filters", text="Filters") - - if (not genericFiltersOnly) and (dopesheet.show_datablock_filters): - row.prop(dopesheet, "show_scenes", text="") - row.prop(dopesheet, "show_worlds", text="") - row.prop(dopesheet, "show_nodes", text="") - - row.prop(dopesheet, "show_transforms", text="") - - if bpy.data.meshes: - row.prop(dopesheet, "show_meshes", text="") - if bpy.data.shape_keys: - row.prop(dopesheet, "show_shapekeys", text="") - if bpy.data.materials: - row.prop(dopesheet, "show_materials", text="") - if bpy.data.lamps: - row.prop(dopesheet, "show_lamps", text="") - if bpy.data.textures: - row.prop(dopesheet, "show_textures", text="") - if bpy.data.cameras: - row.prop(dopesheet, "show_cameras", text="") - if bpy.data.curves: - row.prop(dopesheet, "show_curves", text="") - if bpy.data.metaballs: - row.prop(dopesheet, "show_metaballs", text="") - if bpy.data.lattices: - 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 not genericFiltersOnly: + row = layout.row(align=True) + row.prop(dopesheet, "show_datablock_filters", text="Filters") + + if dopesheet.show_datablock_filters: + row.prop(dopesheet, "show_scenes", text="") + row.prop(dopesheet, "show_worlds", text="") + row.prop(dopesheet, "show_nodes", text="") + + row.prop(dopesheet, "show_transforms", text="") + + if bpy.data.meshes: + row.prop(dopesheet, "show_meshes", text="") + if bpy.data.shape_keys: + row.prop(dopesheet, "show_shapekeys", text="") + if bpy.data.materials: + row.prop(dopesheet, "show_materials", text="") + if bpy.data.lamps: + row.prop(dopesheet, "show_lamps", text="") + if bpy.data.textures: + row.prop(dopesheet, "show_textures", text="") + if bpy.data.cameras: + row.prop(dopesheet, "show_cameras", text="") + if bpy.data.curves: + row.prop(dopesheet, "show_curves", text="") + if bpy.data.metaballs: + row.prop(dopesheet, "show_metaballs", text="") + if bpy.data.lattices: + 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="") ####################################### -- cgit v1.2.3 From aa7545b0ea0920c6ee403d305fc0c0a4af9138ae Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 22 Aug 2011 08:47:48 +0000 Subject: patch [#28320] Small change to trunk needed for Motion Capture Addon - GSoC 2011 - Pepper Branch from Benjy Cook (benjycook) --- release/scripts/startup/bl_operators/nla.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/startup/bl_operators/nla.py b/release/scripts/startup/bl_operators/nla.py index 44ed846e530..714b889da26 100644 --- a/release/scripts/startup/bl_operators/nla.py +++ b/release/scripts/startup/bl_operators/nla.py @@ -84,6 +84,7 @@ def bake(frame_start, do_pose=True, do_object=True, do_constraint_clear=False, + action=None, ): scene = bpy.context.scene @@ -121,7 +122,8 @@ def bake(frame_start, # incase animation data hassnt been created atd = obj.animation_data_create() - action = bpy.data.actions.new("Action") + if action is None: + action = bpy.data.actions.new("Action") atd.action = action if do_pose: -- cgit v1.2.3 From 1324173e99788a168322cd65fb6dc4a3067a3b6a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 22 Aug 2011 09:01:49 +0000 Subject: pep8 edits and change '!= None' to 'is not None' --- release/scripts/modules/bpy_extras/mesh_utils.py | 2 +- .../startup/bl_operators/uvcalc_smart_project.py | 4 ++-- .../scripts/startup/bl_ui/properties_data_camera.py | 2 +- release/scripts/startup/bl_ui/properties_particle.py | 8 ++++---- release/scripts/startup/bl_ui/space_console.py | 2 +- release/scripts/startup/bl_ui/space_dopesheet.py | 2 +- release/scripts/startup/bl_ui/space_image.py | 18 +++++++++--------- release/scripts/startup/bl_ui/space_info.py | 8 ++++---- release/scripts/startup/bl_ui/space_view3d_toolbar.py | 2 +- release/scripts/templates/operator_export.py | 2 +- release/scripts/templates/operator_simple.py | 2 +- 11 files changed, 26 insertions(+), 26 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/bpy_extras/mesh_utils.py b/release/scripts/modules/bpy_extras/mesh_utils.py index c965169ff04..4b5e3eeb066 100644 --- a/release/scripts/modules/bpy_extras/mesh_utils.py +++ b/release/scripts/modules/bpy_extras/mesh_utils.py @@ -426,7 +426,7 @@ def ngon_tesselate(from_data, indices, fix_loops=True): # See if its flipped the wrong way. flip = None for fi in fill: - if flip != None: + if flip is not None: break for i, vi in enumerate(fi): if vi == 0 and fi[i - 1] == 1: diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py index 78b68418322..23838588f43 100644 --- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py +++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py @@ -178,7 +178,7 @@ def pointInEdges(pt, edges): intersectCount = 0 for ed in edges: xi, yi = lineIntersection2D(x1,y1, x2,y2, ed[0][0], ed[0][1], ed[1][0], ed[1][1]) - if xi != None: # Is there an intersection. + if xi is not None: # Is there an intersection. intersectCount+=1 return intersectCount % 2 @@ -1131,7 +1131,7 @@ class SmartProject(Operator): @classmethod def poll(cls, context): - return context.active_object != None + return context.active_object is not None def execute(self, context): main(context, diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py index f484d7b59e1..5255af40951 100644 --- a/release/scripts/startup/bl_ui/properties_data_camera.py +++ b/release/scripts/startup/bl_ui/properties_data_camera.py @@ -107,7 +107,7 @@ class DATA_PT_camera(CameraButtonsPanel, Panel): col = split.column() - if cam.dof_object != None: + if cam.dof_object is not None: col.enabled = False col.prop(cam, "dof_distance", text="Distance") diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py index 03243d1153b..6f58f060504 100644 --- a/release/scripts/startup/bl_ui/properties_particle.py +++ b/release/scripts/startup/bl_ui/properties_particle.py @@ -156,7 +156,7 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel): if part: split = layout.split(percentage=0.65) if part.type == 'HAIR': - if psys != None and psys.is_edited: + if psys is not None and psys.is_edited: split.operator("particle.edited_clear", text="Free Edit") else: row = split.row() @@ -166,12 +166,12 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel): row = split.row() row.enabled = particle_panel_enabled(context, psys) row.prop(part, "hair_step") - if psys != None and psys.is_edited: + if psys is not None and psys.is_edited: if psys.is_global_hair: layout.operator("particle.connect_hair") else: layout.operator("particle.disconnect_hair") - elif psys != None and part.type == 'REACTOR': + 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") @@ -654,7 +654,7 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel): if settings is None: return False - if psys != None and psys.point_cache.use_external: + if psys is not None and psys.point_cache.use_external: return False return settings.physics_type == 'BOIDS' and engine in cls.COMPAT_ENGINES diff --git a/release/scripts/startup/bl_ui/space_console.py b/release/scripts/startup/bl_ui/space_console.py index b517e0d86fb..cbbefa01a3c 100644 --- a/release/scripts/startup/bl_ui/space_console.py +++ b/release/scripts/startup/bl_ui/space_console.py @@ -41,7 +41,7 @@ class CONSOLE_MT_console(Menu): def draw(self, context): layout = self.layout - + layout.operator("console.clear") layout.operator("console.copy") layout.operator("console.paste") diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index dfbd7b3ae14..ae55e1373db 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -101,7 +101,7 @@ class DOPESHEET_HT_header(Header): row.menu("DOPESHEET_MT_select") row.menu("DOPESHEET_MT_marker") - if st.mode == 'DOPESHEET' or (st.mode == 'ACTION' and st.action != None): + if st.mode == 'DOPESHEET' or (st.mode == 'ACTION' and st.action is not None): row.menu("DOPESHEET_MT_channel") elif st.mode == 'GPENCIL': row.menu("DOPESHEET_MT_gpencil_channel") diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index 2042fa1729d..97b5d8457e0 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -452,7 +452,7 @@ class IMAGE_PT_game_properties(Panel): split = layout.split() col = split.column() - + col.prop(ima, "use_animation") sub = col.column(align=True) sub.active = ima.use_animation @@ -507,7 +507,7 @@ class IMAGE_PT_view_waveform(Panel): layout = self.layout sima = context.space_data - + layout.template_waveform(sima, "scopes") row = layout.split(percentage=0.75) row.prop(sima.scopes, "waveform_alpha") @@ -544,9 +544,9 @@ class IMAGE_PT_sample_line(Panel): def draw(self, context): layout = self.layout - + sima = context.space_data - + layout.operator("image.sample_line") layout.template_histogram(sima, "sample_histogram") layout.prop(sima.sample_histogram, "mode") @@ -564,9 +564,9 @@ class IMAGE_PT_scope_sample(Panel): def draw(self, context): layout = self.layout - + sima = context.space_data - + row = layout.row() row.prop(sima.scopes, "use_full_resolution") sub = row.row() @@ -613,14 +613,14 @@ class IMAGE_PT_view_properties(Panel): col = layout.column() col.label("Cursor Location:") col.row().prop(uvedit, "cursor_location", text="") - + col.separator() - + col.label(text="UVs:") col.row().prop(uvedit, "edge_draw_type", expand=True) split = layout.split() - + col = split.column() col.prop(uvedit, "show_faces") col.prop(uvedit, "show_smooth_edges", text="Smooth") diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index 38c1e24f27e..5afc5edf6eb 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -194,7 +194,7 @@ class INFO_MT_mesh_add(Menu): def draw(self, context): layout = self.layout - + layout.operator_context = 'INVOKE_REGION_WIN' layout.operator("mesh.primitive_plane_add", icon='MESH_PLANE', text="Plane") layout.operator("mesh.primitive_cube_add", icon='MESH_CUBE', text="Cube") @@ -215,7 +215,7 @@ class INFO_MT_curve_add(Menu): def draw(self, context): layout = self.layout - + layout.operator_context = 'INVOKE_REGION_WIN' layout.operator("curve.primitive_bezier_curve_add", icon='CURVE_BEZCURVE', text="Bezier") layout.operator("curve.primitive_bezier_circle_add", icon='CURVE_BEZCIRCLE', text="Circle") @@ -246,7 +246,7 @@ class INFO_MT_surface_add(Menu): def draw(self, context): layout = self.layout - + layout.operator_context = 'INVOKE_REGION_WIN' layout.operator("surface.primitive_nurbs_surface_curve_add", icon='SURFACE_NCURVE', text="NURBS Curve") layout.operator("surface.primitive_nurbs_surface_circle_add", icon='SURFACE_NCIRCLE', text="NURBS Circle") @@ -262,7 +262,7 @@ class INFO_MT_armature_add(Menu): def draw(self, context): layout = self.layout - + layout.operator_context = 'INVOKE_REGION_WIN' layout.operator("object.armature_add", text="Single Bone", icon='BONE_DATA') diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 864d59f0cdb..b71593add96 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -1049,7 +1049,7 @@ class VIEW3D_PT_tools_weightpaint(View3DPanel, Panel): ob = context.active_object col = layout.column() - col.active = ob.vertex_groups.active != None + col.active = ob.vertex_groups.active is not None col.operator("object.vertex_group_normalize_all", text="Normalize All") col.operator("object.vertex_group_normalize", text="Normalize") col.operator("object.vertex_group_invert", text="Invert") diff --git a/release/scripts/templates/operator_export.py b/release/scripts/templates/operator_export.py index aeda4ce36fb..b1d53e6ee0c 100644 --- a/release/scripts/templates/operator_export.py +++ b/release/scripts/templates/operator_export.py @@ -47,7 +47,7 @@ class ExportSomeData(bpy.types.Operator, ExportHelper): @classmethod def poll(cls, context): - return context.active_object != None + return context.active_object is not None def execute(self, context): return write_some_data(context, self.filepath, self.use_setting) diff --git a/release/scripts/templates/operator_simple.py b/release/scripts/templates/operator_simple.py index 8348c7a95b1..05d9afc0ad1 100644 --- a/release/scripts/templates/operator_simple.py +++ b/release/scripts/templates/operator_simple.py @@ -13,7 +13,7 @@ class SimpleOperator(bpy.types.Operator): @classmethod def poll(cls, context): - return context.active_object != None + return context.active_object is not None def execute(self, context): main(context) -- cgit v1.2.3 From 5394cabe244bea5c01f03bcf9511fd0a54738a67 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 22 Aug 2011 11:54:40 +0000 Subject: remove workaround for bug in python 3.2.0 loading web pages on *nix --- release/scripts/startup/bl_operators/wm.py | 64 ------------------------------ 1 file changed, 64 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 74f125e0ad3..aa09a088c4f 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -738,7 +738,6 @@ class WM_OT_url_open(Operator): def execute(self, context): import webbrowser - _webbrowser_bug_fix() webbrowser.open(self.url) return {'FINISHED'} @@ -830,7 +829,6 @@ class WM_OT_doc_view(Operator): return {'PASS_THROUGH'} import webbrowser - _webbrowser_bug_fix() webbrowser.open(url) return {'FINISHED'} @@ -1181,65 +1179,3 @@ class WM_OT_copy_prev_settings(Operator): return {'FINISHED'} return {'CANCELLED'} - - -def _webbrowser_bug_fix(): - # test for X11 - import os - - if os.environ.get("DISPLAY"): - - # BSD licenced code copied from python, temp fix for bug - # http://bugs.python.org/issue11432, XXX == added code - def _invoke(self, args, remote, autoraise): - # XXX, added imports - import io - import subprocess - import time - - raise_opt = [] - if remote and self.raise_opts: - # use autoraise argument only for remote invocation - autoraise = int(autoraise) - opt = self.raise_opts[autoraise] - if opt: - raise_opt = [opt] - - cmdline = [self.name] + raise_opt + args - - if remote or self.background: - inout = io.open(os.devnull, "r+") - else: - # for TTY browsers, we need stdin/out - inout = None - # if possible, put browser in separate process group, so - # keyboard interrupts don't affect browser as well as Python - setsid = getattr(os, 'setsid', None) - if not setsid: - setsid = getattr(os, 'setpgrp', None) - - p = subprocess.Popen(cmdline, close_fds=True, # XXX, stdin=inout, - stdout=(self.redirect_stdout and inout or None), - stderr=inout, preexec_fn=setsid) - if remote: - # wait five secons. If the subprocess is not finished, the - # remote invocation has (hopefully) started a new instance. - time.sleep(1) - rc = p.poll() - if rc is None: - time.sleep(4) - rc = p.poll() - if rc is None: - return True - # if remote call failed, open() will try direct invocation - return not rc - elif self.background: - if p.poll() is None: - return True - else: - return False - else: - return not p.wait() - - import webbrowser - webbrowser.UnixBrowser._invoke = _invoke -- cgit v1.2.3 From a71c215f228173070d41faef1321db25b40d723e Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Mon, 22 Aug 2011 18:59:56 +0000 Subject: 3D Audio GSoC: Final GSoC commit. * Bugfix: Negative frames crashed * Bugfix: JOS sample buffer size prediction error (wasted memory) * Optimisation: for JOS upsampling (around 12 % difference measured here) * Optimisation: Better filter for JOS resampling * Bugfix: Error in relative 3D audio code. * Removed Attenuation * Bugfix: Multiple scenes in BGE lead to errors, BGE audio now all relative, to support multiple scenes. --- release/scripts/startup/bl_ui/space_sequencer.py | 1 - 1 file changed, 1 deletion(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index f796ce8da5f..cebe78ff627 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -653,7 +653,6 @@ class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel): layout.prop(strip, "waveform") layout.prop(strip, "volume") - layout.prop(strip, "attenuation") layout.prop(strip, "pitch") layout.prop(strip, "pan") -- cgit v1.2.3 From 6a374d266d8213629f74a9f4c9a4984ddf59ef4c Mon Sep 17 00:00:00 2001 From: Morten Mikkelsen Date: Mon, 22 Aug 2011 19:57:54 +0000 Subject: glsl and render support for derivative maps --- release/scripts/startup/bl_ui/properties_texture.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py index ead65b92c3f..0172fbcbadd 100644 --- a/release/scripts/startup/bl_ui/properties_texture.py +++ b/release/scripts/startup/bl_ui/properties_texture.py @@ -414,6 +414,10 @@ class TEXTURE_PT_image_sampling(TextureTypePanel, Panel): row = col.row() row.active = tex.use_normal_map row.prop(slot, "normal_map_space", text="") + + row = col.row() + row.active = not tex.use_normal_map + row.prop(tex, "use_derivative_map") col.prop(tex, "use_mipmap") row = col.row() @@ -1025,12 +1029,14 @@ class TEXTURE_PT_influence(TextureSlotPanel, Panel): # only show bump settings if activated but not for normalmap images row = layout.row() - row.active = (tex.use_map_normal or tex.use_map_warp) and not (tex.texture.type == 'IMAGE' and tex.texture.use_normal_map) - - row.prop(tex, "bump_method", text="Method") + + sub = row.row() + sub.active = (tex.use_map_normal or tex.use_map_warp) and not (tex.texture.type == 'IMAGE' and (tex.texture.use_normal_map or tex.texture.use_derivative_map)) + sub.prop(tex, "bump_method", text="Method") + # the space setting is supported for: derivmaps + bumpmaps (DEFAULT,BEST_QUALITY), not for normalmaps sub = row.row() - sub.active = tex.bump_method in {'BUMP_DEFAULT', 'BUMP_BEST_QUALITY'} + sub.active = (tex.use_map_normal or tex.use_map_warp) and not (tex.texture.type == 'IMAGE' and tex.texture.use_normal_map) and ((tex.bump_method in {'BUMP_DEFAULT', 'BUMP_BEST_QUALITY'}) or (tex.texture.type == 'IMAGE' and tex.texture.use_derivative_map)) sub.prop(tex, "bump_objectspace", text="Space") -- cgit v1.2.3 From 4740dce4ecad7eb99597a820e6b5e72a17619997 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Mon, 22 Aug 2011 22:26:25 +0000 Subject: Revert a part of 39385. Vertex Select Button got somehow into the Mesh panel. --- release/scripts/startup/bl_ui/properties_data_mesh.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index 896b76c59f6..75df7dad5f2 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -73,7 +73,7 @@ class DATA_PT_context_mesh(MeshButtonsPanel, Panel): ob = context.object mesh = context.mesh space = context.space_data - layout.prop(context.scene.tool_settings, "mesh_select_mode", index=0, text="Vertex") + if ob: layout.template_ID(ob, "data") elif mesh: -- cgit v1.2.3 From 9a9513a9f09f5524235e202a095b04863a07a52b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 23 Aug 2011 19:58:15 +0000 Subject: fix for 3 bugs in bone renaming - renaming a bone could crash if the area had to spaces in it (reported by Sebastian Koenig). - renaming bones wouldn't update inactive 3d views locked bone names. - selecting locked bones in the UI didnt work in editmode. --- release/scripts/startup/bl_ui/space_view3d.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index fa22e216ec9..dd705f76feb 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -2073,9 +2073,11 @@ class VIEW3D_PT_view3d_properties(Panel): col.prop(view, "lens") col.label(text="Lock to Object:") col.prop(view, "lock_object", text="") - if view.lock_object and view.lock_object.type == 'ARMATURE': - col.prop_search(view, "lock_bone", view.lock_object.data, "bones", text="") - elif not view.lock_object: + lock_object = view.lock_object + if lock_object: + if lock_object.type == 'ARMATURE': + col.prop_search(view, "lock_bone", lock_object.data, "edit_bones" if lock_object.mode == 'EDIT' else "bones", text="") + else: col.prop(view, "lock_cursor", text="Lock to Cursor") col = layout.column() -- cgit v1.2.3 From 291ae8822d5ff2fafbb53568c040828058cee0db Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 25 Aug 2011 17:59:37 +0000 Subject: executing operators that changed the context from the console wasnt returning an operator set/flag. --- release/scripts/modules/console_python.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'release') diff --git a/release/scripts/modules/console_python.py b/release/scripts/modules/console_python.py index 455eabe377b..425ea210104 100644 --- a/release/scripts/modules/console_python.py +++ b/release/scripts/modules/console_python.py @@ -179,7 +179,7 @@ def execute(context): # special exception. its possible the command loaded a new user interface if hash(sc) != hash(context.space_data): - return + return {'FINISHED'} bpy.ops.console.scrollback_append(text=sc.prompt + line, type='INPUT') -- cgit v1.2.3 From a9dea3afe9ca590e3d2d6788066d52dab3fd872c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 26 Aug 2011 18:48:48 +0000 Subject: correct missing bpy doc references. --- release/scripts/modules/bpy_extras/image_utils.py | 2 +- release/scripts/modules/bpy_extras/io_utils.py | 4 ++-- release/scripts/modules/bpy_extras/mesh_utils.py | 8 ++++---- release/scripts/modules/bpy_extras/object_utils.py | 12 ++++++------ release/scripts/modules/bpy_extras/view3d_utils.py | 18 +++++++++--------- release/scripts/modules/bpy_types.py | 2 +- 6 files changed, 23 insertions(+), 23 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/bpy_extras/image_utils.py b/release/scripts/modules/bpy_extras/image_utils.py index eab75c3bd16..02959fae534 100644 --- a/release/scripts/modules/bpy_extras/image_utils.py +++ b/release/scripts/modules/bpy_extras/image_utils.py @@ -58,7 +58,7 @@ def load_image(imagepath, For formats blender can read, simply return the path that is given. :type convert_callback: function :return: an image or None - :rtype: :class:`Image` + :rtype: :class:`bpy.types.Image` """ import os import bpy diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py index 6271c1f77b5..3f6a3682e7c 100644 --- a/release/scripts/modules/bpy_extras/io_utils.py +++ b/release/scripts/modules/bpy_extras/io_utils.py @@ -252,10 +252,10 @@ def axis_conversion(from_forward='Y', from_up='Z', to_forward='Y', to_up='Z'): def axis_conversion_ensure(operator, forward_attr, up_attr): """ Function to ensure an operator has valid axis conversion settings, intended - to be used from :class:`Operator.check`. + to be used from :class:`bpy.types.Operator.check`. :arg operator: the operator to access axis attributes from. - :type operator: :class:`Operator` + :type operator: :class:`bpy.types.Operator` :arg forward_attr: attribute storing the forward axis :type forward_attr: string :arg up_attr: attribute storing the up axis diff --git a/release/scripts/modules/bpy_extras/mesh_utils.py b/release/scripts/modules/bpy_extras/mesh_utils.py index 4b5e3eeb066..7bc6dae3cc6 100644 --- a/release/scripts/modules/bpy_extras/mesh_utils.py +++ b/release/scripts/modules/bpy_extras/mesh_utils.py @@ -35,7 +35,7 @@ def mesh_linked_faces(mesh): other mesh elements within 1 mesh datablock. :arg mesh: the mesh used to group with. - :type mesh: :class:`Mesh` + :type mesh: :class:`bpy.types.Mesh` :return: lists of lists containing faces. :rtype: list """ @@ -125,9 +125,9 @@ def edge_loops_from_faces(mesh, faces=None, seams=()): [[(0, 1), (4, 8), (3, 8)], ...] :arg mesh: the mesh used to get edge loops from. - :type mesh: :class:`Mesh` + :type mesh: :class:`bpy.types.Mesh` :arg faces: optional face list to only use some of the meshes faces. - :type faces: :class:`MeshFaces`, sequence or or NoneType + :type faces: :class:`bpy.types.MeshFaces`, sequence or or NoneType :return: return a list of edge vertex index lists. :rtype: list """ @@ -450,7 +450,7 @@ def face_random_points(num_points, faces): :arg num_points: the number of random points to generate on each face. :type int: :arg faces: list of the faces to generate points on. - :type faces: :class:`MeshFaces`, sequence + :type faces: :class:`bpy.types.MeshFaces`, sequence :return: list of random points over all faces. :rtype: list """ diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py index 790f5ba48cb..3081e6f172e 100644 --- a/release/scripts/modules/bpy_extras/object_utils.py +++ b/release/scripts/modules/bpy_extras/object_utils.py @@ -33,11 +33,11 @@ def add_object_align_init(context, operator): Return a matrix using the operator settings and view context. :arg context: The context to use. - :type context: :class:`Context` + :type context: :class:`bpy.types.Context` :arg operator: The operator, checked for location and rotation properties. - :type operator: :class:`Operator` + :type operator: :class:`bpy.types.Operator` :return: the matrix from the context and settings. - :rtype: :class:`Matrix` + :rtype: :class:`mathutils.Matrix` """ from mathutils import Matrix, Vector, Euler @@ -92,13 +92,13 @@ def object_data_add(context, obdata, operator=None): location, rotation and layer. :arg context: The context to use. - :type context: :class:`Context` + :type context: :class:`bpy.types.Context` :arg obdata: the data used for the new object. :type obdata: valid object data type or None. :arg operator: The operator, checked for location and rotation properties. - :type operator: :class:`Operator` + :type operator: :class:`bpy.types.Operator` :return: the newly created object in the scene. - :rtype: :class:`ObjectBase` + :rtype: :class:`bpy.types.ObjectBase` """ scene = context.scene diff --git a/release/scripts/modules/bpy_extras/view3d_utils.py b/release/scripts/modules/bpy_extras/view3d_utils.py index 26325633a05..c18a74bbb09 100644 --- a/release/scripts/modules/bpy_extras/view3d_utils.py +++ b/release/scripts/modules/bpy_extras/view3d_utils.py @@ -31,14 +31,14 @@ def region_2d_to_vector_3d(region, rv3d, coord): coordinate. :arg region: region of the 3D viewport, typically bpy.context.region. - :type region: :class:`Region` + :type region: :class:`bpy.types.Region` :arg rv3d: 3D region data, typically bpy.context.space_data.region_3d. - :type rv3d: :class:`RegionView3D` + :type rv3d: :class:`bpy.types.RegionView3D` :arg coord: 2d coordinates relative to the region: (event.mouse_region_x, event.mouse_region_y) for example. :type coord: 2d vector :return: normalized 3d vector. - :rtype: :class:`Vector` + :rtype: :class:`mathutils.Vector` """ from mathutils import Vector @@ -65,9 +65,9 @@ def region_2d_to_location_3d(region, rv3d, coord, depth_location): *depth_location*. :arg region: region of the 3D viewport, typically bpy.context.region. - :type region: :class:`Region` + :type region: :class:`bpy.types.Region` :arg rv3d: 3D region data, typically bpy.context.space_data.region_3d. - :type rv3d: :class:`RegionView3D` + :type rv3d: :class:`bpy.types.RegionView3D` :arg coord: 2d coordinates relative to the region; (event.mouse_region_x, event.mouse_region_y) for example. :type coord: 2d vector @@ -75,7 +75,7 @@ def region_2d_to_location_3d(region, rv3d, coord, depth_location): there is no defined depth with a 2d region input. :type depth_location: 3d vector :return: normalized 3d vector. - :rtype: :class:`Vector` + :rtype: :class:`mathutils.Vector` """ from mathutils import Vector from mathutils.geometry import intersect_point_line @@ -114,13 +114,13 @@ def location_3d_to_region_2d(region, rv3d, coord): Return the *region* relative 2d location of a 3d position. :arg region: region of the 3D viewport, typically bpy.context.region. - :type region: :class:`Region` + :type region: :class:`bpy.types.Region` :arg rv3d: 3D region data, typically bpy.context.space_data.region_3d. - :type rv3d: :class:`RegionView3D` + :type rv3d: :class:`bpy.types.RegionView3D` :arg coord: 3d worldspace location. :type coord: 3d vector :return: 2d location - :rtype: :class:`Vector` + :rtype: :class:`mathutils.Vector` """ from mathutils import Vector diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 8766c873dd8..e8c58105d94 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -287,7 +287,7 @@ class EditBone(StructRNA, _GenericBone, metaclass=StructMetaPropGroup): Transform the the bones head, tail, roll and envalope (when the matrix has a scale component). :arg matrix: 3x3 or 4x4 transformation matrix. - :type matrix: :class:`Matrix` + :type matrix: :class:`mathutils.Matrix` :arg scale: Scale the bone envalope by the matrix. :type scale: bool :arg roll: Correct the roll to point in the same relative direction to the head and tail. -- cgit v1.2.3 From 752cb7485de8d06b261084eac3ab1c259a20ead3 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Sat, 27 Aug 2011 12:01:01 +0000 Subject: Do not show confirm message when creating text block from menu. --- release/scripts/startup/bl_ui/space_text.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py index 300211a26bf..12e07c19ca1 100644 --- a/release/scripts/startup/bl_ui/space_text.py +++ b/release/scripts/startup/bl_ui/space_text.py @@ -172,7 +172,9 @@ class TEXT_MT_text(Menu): st = context.space_data text = st.text + layout.operator_context = 'EXEC_AREA' layout.operator("text.new") + layout.operator_context = 'INVOKE_AREA' layout.operator("text.open") if text: -- cgit v1.2.3 From b4b046995b21d59e315eb71ed08fc1ae066c891b Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Sun, 28 Aug 2011 14:21:44 +0000 Subject: * Removing mocap GSoC (is an addon already). * Fixing ffmpeg-0.8 errors. * Fixing Ketsji paths. * Removing DoSound from BGE. * Fixing audio scene update to use only current scene objects. --- release/scripts/modules/mocap_constraints.py | 434 ------------- release/scripts/modules/mocap_tools.py | 904 --------------------------- release/scripts/modules/retarget.py | 559 ----------------- release/scripts/startup/ui_mocap.py | 850 ------------------------- 4 files changed, 2747 deletions(-) delete mode 100644 release/scripts/modules/mocap_constraints.py delete mode 100644 release/scripts/modules/mocap_tools.py delete mode 100644 release/scripts/modules/retarget.py delete mode 100644 release/scripts/startup/ui_mocap.py (limited to 'release') diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py deleted file mode 100644 index 540e8fa06db..00000000000 --- a/release/scripts/modules/mocap_constraints.py +++ /dev/null @@ -1,434 +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 ##### - -# - -import bpy -from mathutils import * -from bl_operators import nla -from retarget import hasIKConstraint - -### Utility Functions - - -def getConsObj(bone): - #utility function - returns related IK target if bone has IK - ik = [constraint for constraint in bone.constraints if constraint.type == "IK"] - if ik: - ik = ik[0] - cons_obj = ik.target - if ik.subtarget: - cons_obj = ik.target.pose.bones[ik.subtarget] - else: - cons_obj = bone - return cons_obj - - -def consObjToBone(cons_obj): - #Utility function - returns related bone from ik object - if cons_obj.name[-3:] == "Org": - return cons_obj.name[:-3] - else: - return cons_obj.name - -### And and Remove Constraints (called from operators) - - -def addNewConstraint(m_constraint, cons_obj): - #Decide the correct Blender constraint according to the Mocap constraint type - if m_constraint.type == "point" or m_constraint.type == "freeze": - c_type = "LIMIT_LOCATION" - if m_constraint.type == "distance": - c_type = "LIMIT_DISTANCE" - if m_constraint.type == "floor": - c_type = "LIMIT_LOCATION" - #create and store the new constraint within m_constraint - real_constraint = cons_obj.constraints.new(c_type) - real_constraint.name = "Auto fixes " + str(len(cons_obj.constraints)) - m_constraint.real_constraint_bone = consObjToBone(cons_obj) - m_constraint.real_constraint = real_constraint.name - #set the rest of the constraint properties - setConstraint(m_constraint, bpy.context) - - -def removeConstraint(m_constraint, cons_obj): - #remove the influence fcurve and Blender constraint - oldConstraint = cons_obj.constraints[m_constraint.real_constraint] - removeFcurves(cons_obj, bpy.context.active_object, oldConstraint, m_constraint) - cons_obj.constraints.remove(oldConstraint) - -### Update functions. There are 3: UpdateType/Bone -### update framing (deals with changes in the desired frame range) -### And setConstraint which deals with the rest - - -def updateConstraintBoneType(m_constraint, context): - #If the constraint exists, we need to remove it - #from the old bone - obj = context.active_object - bones = obj.pose.bones - if m_constraint.real_constraint: - bone = bones[m_constraint.real_constraint_bone] - cons_obj = getConsObj(bone) - removeConstraint(m_constraint, cons_obj) - #Regardless, after that we create a new constraint - if m_constraint.constrained_bone: - bone = bones[m_constraint.constrained_bone] - cons_obj = getConsObj(bone) - addNewConstraint(m_constraint, cons_obj) - - -def setConstraintFraming(m_constraint, context): - obj = context.active_object - bones = obj.pose.bones - bone = bones[m_constraint.constrained_bone] - cons_obj = getConsObj(bone) - real_constraint = cons_obj.constraints[m_constraint.real_constraint] - #remove the old keyframes - removeFcurves(cons_obj, obj, real_constraint, m_constraint) - #set the new ones according to the m_constraint properties - s, e = m_constraint.s_frame, m_constraint.e_frame - s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out - real_constraint.influence = 1 - real_constraint.keyframe_insert(data_path="influence", frame=s) - real_constraint.keyframe_insert(data_path="influence", frame=e) - real_constraint.influence = 0 - real_constraint.keyframe_insert(data_path="influence", frame=s - s_in) - real_constraint.keyframe_insert(data_path="influence", frame=e + s_out) - - -def removeFcurves(cons_obj, obj, real_constraint, m_constraint): - #Determine if the constrained object is a bone or an empty - if isinstance(cons_obj, bpy.types.PoseBone): - fcurves = obj.animation_data.action.fcurves - else: - fcurves = cons_obj.animation_data.action.fcurves - #Find the RNA data path of the constraint's influence - RNA_paths = [] - RNA_paths.append(real_constraint.path_from_id("influence")) - if m_constraint.type == "floor" or m_constraint.type == "point": - RNA_paths += [real_constraint.path_from_id("max_x"), real_constraint.path_from_id("min_x")] - RNA_paths += [real_constraint.path_from_id("max_y"), real_constraint.path_from_id("min_y")] - RNA_paths += [real_constraint.path_from_id("max_z"), real_constraint.path_from_id("min_z")] - #Retrieve the correct fcurve via the RNA data path and remove it - fcurves_del = [fcurve for fcurve in fcurves if fcurve.data_path in RNA_paths] - #clear the fcurve and set the frames. - if fcurves_del: - for fcurve in fcurves_del: - fcurves.remove(fcurve) - #remove armature fcurves (if user keyframed m_constraint properties) - if obj.data.animation_data and m_constraint.type == "point": - if obj.data.animation_data.action: - path = m_constraint.path_from_id("targetPoint") - m_fcurves = [fcurve for fcurve in obj.data.animation_data.action.fcurves if fcurve.data_path == path] - for curve in m_fcurves: - obj.data.animation_data.action.fcurves.remove(curve) - -#Utility function for copying property fcurves over - - -def copyFCurve(newCurve, oldCurve): - for point in oldCurve.keyframe_points: - newCurve.keyframe_points.insert(frame=point.co.x, value=point.co.y) - -#Creates new fcurves for the constraint properties (for floor and point) - - -def createConstraintFCurves(cons_obj, obj, real_constraint): - if isinstance(cons_obj, bpy.types.PoseBone): - c_fcurves = obj.animation_data.action.fcurves - else: - c_fcurves = cons_obj.animation_data.action.fcurves - c_x_path = [real_constraint.path_from_id("max_x"), real_constraint.path_from_id("min_x")] - c_y_path = [real_constraint.path_from_id("max_y"), real_constraint.path_from_id("min_y")] - c_z_path = [real_constraint.path_from_id("max_z"), real_constraint.path_from_id("min_z")] - c_constraints_path = c_x_path + c_y_path + c_z_path - existing_curves = [fcurve for fcurve in c_fcurves if fcurve.data_path in c_constraints_path] - if existing_curves: - for curve in existing_curves: - c_fcurves.remove(curve) - xCurves, yCurves, zCurves = [], [], [] - for path in c_constraints_path: - newCurve = c_fcurves.new(path) - if path in c_x_path: - xCurves.append(newCurve) - elif path in c_y_path: - yCurves.append(newCurve) - else: - zCurves.append(newCurve) - return xCurves, yCurves, zCurves - - -# Function that copies all settings from m_constraint to the real Blender constraints -# Is only called when blender constraint already exists - - -def setConstraint(m_constraint, context): - if not m_constraint.constrained_bone: - return - obj = context.active_object - bones = obj.pose.bones - bone = bones[m_constraint.constrained_bone] - cons_obj = getConsObj(bone) - real_constraint = cons_obj.constraints[m_constraint.real_constraint] - NLATracks = obj.data.mocapNLATracks[obj.data.active_mocap] - obj.animation_data.action = bpy.data.actions[NLATracks.auto_fix_track] - - #frame changing section - setConstraintFraming(m_constraint, context) - s, e = m_constraint.s_frame, m_constraint.e_frame - s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out - s -= s_in - e += s_out - #Set the blender constraint parameters - if m_constraint.type == "point": - constraint_settings = False # are fix settings keyframed? - if not m_constraint.targetSpace == "constrained_boneB": - real_constraint.owner_space = m_constraint.targetSpace - else: - real_constraint.owner_space = "LOCAL" - if obj.data.animation_data: - if obj.data.animation_data.action: - path = m_constraint.path_from_id("targetPoint") - m_fcurves = [fcurve for fcurve in obj.data.animation_data.action.fcurves if fcurve.data_path == path] - if m_fcurves: - constraint_settings = True - xCurves, yCurves, zCurves = createConstraintFCurves(cons_obj, obj, real_constraint) - for curve in xCurves: - copyFCurve(curve, m_fcurves[0]) - for curve in yCurves: - copyFCurve(curve, m_fcurves[1]) - for curve in zCurves: - copyFCurve(curve, m_fcurves[2]) - if m_constraint.targetSpace == "constrained_boneB" and m_constraint.constrained_boneB: - c_frame = context.scene.frame_current - bakedPos = {} - src_bone = bones[m_constraint.constrained_boneB] - if not constraint_settings: - xCurves, yCurves, zCurves = createConstraintFCurves(cons_obj, obj, real_constraint) - print("please wait a moment, calculating fix") - for t in range(s, e): - context.scene.frame_set(t) - src_bone_pos = src_bone.matrix.to_translation() - bakedPos[t] = src_bone_pos + m_constraint.targetPoint # final position for constrained bone in object space - context.scene.frame_set(c_frame) - for frame in bakedPos.keys(): - pos = bakedPos[frame] - for xCurve in xCurves: - xCurve.keyframe_points.insert(frame=frame, value=pos.x) - for yCurve in yCurves: - yCurve.keyframe_points.insert(frame=frame, value=pos.y) - for zCurve in zCurves: - zCurve.keyframe_points.insert(frame=frame, value=pos.z) - - if not constraint_settings: - x, y, z = m_constraint.targetPoint - real_constraint.max_x = x - real_constraint.max_y = y - real_constraint.max_z = z - real_constraint.min_x = x - real_constraint.min_y = y - real_constraint.min_z = z - real_constraint.use_max_x = True - real_constraint.use_max_y = True - real_constraint.use_max_z = True - real_constraint.use_min_x = True - real_constraint.use_min_y = True - real_constraint.use_min_z = True - - if m_constraint.type == "freeze": - real_constraint.owner_space = m_constraint.targetSpace - bpy.context.scene.frame_set(m_constraint.s_frame) - if isinstance(cons_obj, bpy.types.PoseBone): - x, y, z = cons_obj.bone.center + (cons_obj.bone.vector / 2) + obj.matrix_world.to_translation() - else: - x, y, z = cons_obj.matrix_world.to_translation() - - real_constraint.max_x = x - real_constraint.max_y = y - real_constraint.max_z = z - real_constraint.min_x = x - real_constraint.min_y = y - real_constraint.min_z = z - real_constraint.use_max_x = True - real_constraint.use_max_y = True - real_constraint.use_max_z = True - real_constraint.use_min_x = True - real_constraint.use_min_y = True - real_constraint.use_min_z = True - - if m_constraint.type == "distance" and m_constraint.constrained_boneB: - real_constraint.owner_space = "WORLD" - real_constraint.target = getConsObj(bones[m_constraint.constrained_boneB]) - real_constraint.limit_mode = "LIMITDIST_ONSURFACE" - real_constraint.distance = m_constraint.targetDist - - if m_constraint.type == "floor" and m_constraint.targetMesh: - real_constraint.mute = True - real_constraint.owner_space = "WORLD" - #calculate the positions thoughout the range - s, e = m_constraint.s_frame, m_constraint.e_frame - s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out - s -= s_in - e += s_out - bakedPos = {} - floor = bpy.data.objects[m_constraint.targetMesh] - c_frame = context.scene.frame_current - print("please wait a moment, calculating fix") - for t in range(s, e): - context.scene.frame_set(t) - axis = Vector((0, 0, 100)) * obj.matrix_world.to_3x3() - offset = Vector((0, 0, m_constraint.targetDist)) * obj.matrix_world.to_3x3() - ray_origin = cons_obj.matrix_world.to_translation() - offset # world position of constrained bone - ray_target = ray_origin + axis - #convert ray points to floor's object space - ray_origin *= floor.matrix_world.inverted() - ray_target *= floor.matrix_world.inverted() - hit, nor, ind = floor.ray_cast(ray_origin, ray_target) - if hit != Vector((0, 0, 0)): - bakedPos[t] = (hit * floor.matrix_world) - bakedPos[t] += Vector((0, 0, m_constraint.targetDist)) - else: - bakedPos[t] = cons_obj.matrix_world.to_translation() - context.scene.frame_set(c_frame) - #create keyframes for real constraint - xCurves, yCurves, zCurves = createConstraintFCurves(cons_obj, obj, real_constraint) - for frame in bakedPos.keys(): - pos = bakedPos[frame] - for xCurve in xCurves: - xCurve.keyframe_points.insert(frame=frame, value=pos.x) - for yCurve in yCurves: - yCurve.keyframe_points.insert(frame=frame, value=pos.y) - for zCurve in zCurves: - zCurve.keyframe_points.insert(frame=frame, value=pos.z) - real_constraint.use_max_x = True - real_constraint.use_max_y = True - real_constraint.use_max_z = True - real_constraint.use_min_x = True - real_constraint.use_min_y = True - real_constraint.use_min_z = True - - # active/baked check - real_constraint.mute = (not m_constraint.active) - - -def locBake(s_frame, e_frame, bones): - scene = bpy.context.scene - bakeDict = {} - for bone in bones: - bakeDict[bone.name] = {} - for t in range(s_frame, e_frame): - scene.frame_set(t) - for bone in bones: - bakeDict[bone.name][t] = bone.matrix.copy() - for t in range(s_frame, e_frame): - for bone in bones: - print(bone.bone.matrix_local.to_translation()) - bone.matrix = bakeDict[bone.name][t] - bone.keyframe_insert("location", frame=t) - - -# Baking function which bakes all bones effected by the constraint -def bakeAllConstraints(obj, s_frame, e_frame, bones): - for bone in bones: - bone.bone.select = False - selectedBones = [] # Marks bones that need a full bake - simpleBake = [] # Marks bones that need only a location bake - for end_bone in bones: - if end_bone.name in [m_constraint.real_constraint_bone for m_constraint in obj.data.mocap_constraints]: - #For all bones that have a constraint: - ik = hasIKConstraint(end_bone) - cons_obj = getConsObj(end_bone) - if ik: - #If it's an auto generated IK: - if ik.chain_count == 0: - selectedBones += bones # Chain len 0, bake everything - else: - selectedBones += [end_bone] + end_bone.parent_recursive[:ik.chain_count - 1] # Bake the chain - else: - #It's either an FK bone which we should just bake - #OR a user created IK target bone - simpleBake += [end_bone] - for bone in selectedBones: - bone.bone.select = True - NLATracks = obj.data.mocapNLATracks[obj.data.active_mocap] - obj.animation_data.action = bpy.data.actions[NLATracks.auto_fix_track] - constraintTrack = obj.animation_data.nla_tracks[NLATracks.auto_fix_track] - constraintStrip = constraintTrack.strips[0] - constraintStrip.action_frame_start = s_frame - constraintStrip.action_frame_end = e_frame - constraintStrip.frame_start = s_frame - constraintStrip.frame_end = e_frame - if selectedBones: - #Use bake function from NLA Bake Action operator - nla.bake(s_frame, e_frame, action=constraintStrip.action, only_selected=True, do_pose=True, do_object=False) - if simpleBake: - #Do a "simple" bake, location only, world space only. - locBake(s_frame, e_frame, simpleBake) - - -#Calls the baking function and decativates releveant constraints -def bakeConstraints(context): - obj = context.active_object - bones = obj.pose.bones - s_frame, e_frame = context.scene.frame_start, context.scene.frame_end - #Bake relevant bones - bakeAllConstraints(obj, s_frame, e_frame, bones) - for m_constraint in obj.data.mocap_constraints: - end_bone = bones[m_constraint.real_constraint_bone] - cons_obj = getConsObj(end_bone) - # It's a control empty: turn the ik off - if not isinstance(cons_obj, bpy.types.PoseBone): - ik_con = hasIKConstraint(end_bone) - if ik_con: - ik_con.mute = True - # Deactivate related Blender Constraint - m_constraint.active = False - - -#Deletes the baked fcurves and reactivates relevant constraints -def unbakeConstraints(context): - # to unbake constraints we delete the whole strip - obj = context.active_object - bones = obj.pose.bones - scene = bpy.context.scene - NLATracks = obj.data.mocapNLATracks[obj.data.active_mocap] - obj.animation_data.action = bpy.data.actions[NLATracks.auto_fix_track] - constraintTrack = obj.animation_data.nla_tracks[NLATracks.auto_fix_track] - constraintStrip = constraintTrack.strips[0] - action = constraintStrip.action - # delete the fcurves on the strip - for fcurve in action.fcurves: - action.fcurves.remove(fcurve) - # reactivate relevant constraints - for m_constraint in obj.data.mocap_constraints: - end_bone = bones[m_constraint.real_constraint_bone] - cons_obj = getConsObj(end_bone) - # It's a control empty: turn the ik back on - if not isinstance(cons_obj, bpy.types.PoseBone): - ik_con = hasIKConstraint(end_bone) - if ik_con: - ik_con.mute = False - m_constraint.active = True - - -def updateConstraints(obj, context): - fixes = obj.data.mocap_constraints - for fix in fixes: - fix.active = False - fix.active = True diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py deleted file mode 100644 index 6c22f718296..00000000000 --- a/release/scripts/modules/mocap_tools.py +++ /dev/null @@ -1,904 +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 ##### - -# - -from math import hypot, sqrt, isfinite, radians, pi -import bpy -import time -from mathutils import Vector, Matrix - - -# A Python implementation of n sized Vectors. -# Mathutils has a max size of 4, and we need at least 5 for Simplify Curves and even more for Cross Correlation. -# Vector utility functions -class NdVector: - vec = [] - - def __init__(self, vec): - self.vec = vec[:] - - def __len__(self): - return len(self.vec) - - def __mul__(self, otherMember): - if (isinstance(otherMember, int) or - isinstance(otherMember, float)): - return NdVector([otherMember * x for x in self.vec]) - else: - a = self.vec - b = otherMember.vec - n = len(self) - return sum([a[i] * b[i] for i in range(n)]) - - def __sub__(self, otherVec): - a = self.vec - b = otherVec.vec - n = len(self) - return NdVector([a[i] - b[i] for i in range(n)]) - - def __add__(self, otherVec): - a = self.vec - b = otherVec.vec - n = len(self) - return NdVector([a[i] + b[i] for i in range(n)]) - - def __div__(self, scalar): - return NdVector([x / scalar for x in self.vec]) - - def vecLength(self): - return sqrt(self * self) - - def vecLengthSq(self): - return (self * self) - - def normalize(self): - len = self.length - self.vec = [x / len for x in self.vec] - - def copy(self): - return NdVector(self.vec) - - def __getitem__(self, i): - return self.vec[i] - - def x(self): - return self.vec[0] - - def y(self): - return self.vec[1] - - def resize_2d(self): - return Vector((self.x, self.y)) - - length = property(vecLength) - lengthSq = property(vecLengthSq) - x = property(x) - y = property(y) - - -#Sampled Data Point class for Simplify Curves -class dataPoint: - index = 0 - # x,y1,y2,y3 coordinate of original point - co = NdVector((0, 0, 0, 0, 0)) - #position according to parametric view of original data, [0,1] range - u = 0 - #use this for anything - temp = 0 - - def __init__(self, index, co, u=0): - self.index = index - self.co = co - self.u = u - - -#Cross Correlation Function -#http://en.wikipedia.org/wiki/Cross_correlation -#IN: curvesA, curvesB - bpy_collection/list of fcurves to analyze. Auto-Correlation is when they are the same. -# margin - When searching for the best "start" frame, how large a neighborhood of frames should we inspect (similar to epsilon in Calculus) -#OUT: startFrame, length of new anim, and curvesA -def crossCorrelationMatch(curvesA, curvesB, margin): - dataA = [] - dataB = [] - start, end = curvesA[0].range() - start = int(start) - end = int(end) - - #transfer all fcurves data on each frame to a single NdVector. - for i in range(1, end): - vec = [] - for fcurve in curvesA: - vec.append(fcurve.evaluate(i)) - dataA.append(NdVector(vec)) - vec = [] - for fcurve in curvesB: - vec.append(fcurve.evaluate(i)) - dataB.append(NdVector(vec)) - - #Comparator for Cross Correlation. "Classic" implementation uses dot product, as do we. - def comp(a, b): - return a * b - - #Create Rxy, which holds the Cross Correlation data. - N = len(dataA) - Rxy = [0.0] * N - for i in range(N): - for j in range(i, min(i + N, N)): - Rxy[i] += comp(dataA[j], dataB[j - i]) - for j in range(i): - Rxy[i] += comp(dataA[j], dataB[j - i + N]) - Rxy[i] /= float(N) - - #Find the Local maximums in the Cross Correlation data via numerical derivative. - def LocalMaximums(Rxy): - Rxyd = [Rxy[i] - Rxy[i - 1] for i in range(1, len(Rxy))] - maxs = [] - for i in range(1, len(Rxyd) - 1): - a = Rxyd[i - 1] - b = Rxyd[i] - #sign change (zerocrossing) at point i, denoting max point (only) - if (a >= 0 and b < 0) or (a < 0 and b >= 0): - maxs.append((i, max(Rxy[i], Rxy[i - 1]))) - return [x[0] for x in maxs] - #~ return max(maxs, key=lambda x: x[1])[0] - - #flms - the possible offsets of the first part of the animation. In Auto-Corr, this is the length of the loop. - flms = LocalMaximums(Rxy[0:int(len(Rxy))]) - ss = [] - - #for every local maximum, find the best one - i.e. also has the best start frame. - for flm in flms: - diff = [] - - for i in range(len(dataA) - flm): - diff.append((dataA[i] - dataB[i + flm]).lengthSq) - - def lowerErrorSlice(diff, e): - #index, error at index - bestSlice = (0, 100000) - for i in range(e, len(diff) - e): - errorSlice = sum(diff[i - e:i + e + 1]) - if errorSlice < bestSlice[1]: - bestSlice = (i, errorSlice, flm) - return bestSlice - - s = lowerErrorSlice(diff, margin) - ss.append(s) - - #Find the best result and return it. - ss.sort(key=lambda x: x[1]) - return ss[0][2], ss[0][0], dataA - - -#Uses auto correlation (cross correlation of the same set of curves) and trims the active_object's fcurves -#Except for location curves (which in mocap tend to be not cyclic, e.g. a walk cycle forward) -#Transfers the fcurve data to a list of NdVector (length of list is number of fcurves), and calls the cross correlation function. -#Then trims the fcurve accordingly. -#IN: Nothing, set the object you want as active and call. Assumes object has animation_data.action! -#OUT: Trims the object's fcurves (except location curves). -def autoloop_anim(): - context = bpy.context - obj = context.active_object - - def locCurve(x): - x.data_path == "location" - - fcurves = [x for x in obj.animation_data.action.fcurves if not locCurve(x)] - - margin = 10 - - flm, s, data = crossCorrelationMatch(fcurves, fcurves, margin) - loop = data[s:s + flm] - - #performs blending with a root falloff on the seam's neighborhood to ensure good tiling. - for i in range(1, margin + 1): - w1 = sqrt(float(i) / margin) - loop[-i] = (loop[-i] * w1) + (loop[0] * (1 - w1)) - - for curve in fcurves: - pts = curve.keyframe_points - for i in range(len(pts) - 1, -1, -1): - pts.remove(pts[i]) - - for c, curve in enumerate(fcurves): - pts = curve.keyframe_points - for i in range(len(loop)): - pts.insert(i + 2, loop[i][c]) - - context.scene.frame_end = flm - - -#simplifyCurves: performes the bulk of the samples to bezier conversion. -#IN: curveGroup - which can be a collection of singleFcurves, or grouped (via nested lists) . -# error - threshold of permittable error (max distance) of the new beziers to the original data -# reparaError - threshold of error where we should try to fix the parameterization rather than split the existing curve. > error, usually by a small constant factor for best performance. -# maxIterations - maximum number of iterations of reparameterizations we should attempt. (Newton-Rahpson is not guarenteed to converge, so this is needed). -# group_mode - boolean, indicating wether we should place bezier keyframes on the same x (frame), or optimize each individual curve. -#OUT: None. Deletes the existing curves and creates the new beziers. -def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): - - #Calculates the unit tangent of point v - def unitTangent(v, data_pts): - tang = NdVector((0, 0, 0, 0, 0)) - if v != 0: - #If it's not the first point, we can calculate a leftside tangent - tang += data_pts[v].co - data_pts[v - 1].co - if v != len(data_pts) - 1: - #If it's not the last point, we can calculate a rightside tangent - tang += data_pts[v + 1].co - data_pts[v].co - tang.normalize() - return tang - - #assign parametric u value for each point in original data, via relative arc length - #http://en.wikipedia.org/wiki/Arc_length - def chordLength(data_pts, s, e): - totalLength = 0 - for pt in data_pts[s:e + 1]: - i = pt.index - if i == s: - chordLength = 0 - else: - chordLength = (data_pts[i].co - data_pts[i - 1].co).length - totalLength += chordLength - pt.temp = totalLength - for pt in data_pts[s:e + 1]: - if totalLength == 0: - print(s, e) - pt.u = (pt.temp / totalLength) - - # get binomial coefficient lookup table, this function/table is only called with args - # (3,0),(3,1),(3,2),(3,3),(2,0),(2,1),(2,2)! - binomDict = {(3, 0): 1, - (3, 1): 3, - (3, 2): 3, - (3, 3): 1, - (2, 0): 1, - (2, 1): 2, - (2, 2): 1} - - #value at pt t of a single bernstein Polynomial - def bernsteinPoly(n, i, t): - binomCoeff = binomDict[(n, i)] - return binomCoeff * pow(t, i) * pow(1 - t, n - i) - - # fit a single cubic to data points in range [s(tart),e(nd)]. - def fitSingleCubic(data_pts, s, e): - - # A - matrix used for calculating C matrices for fitting - def A(i, j, s, e, t1, t2): - if j == 1: - t = t1 - if j == 2: - t = t2 - u = data_pts[i].u - return t * bernsteinPoly(3, j, u) - - # X component, used for calculating X matrices for fitting - def xComponent(i, s, e): - di = data_pts[i].co - u = data_pts[i].u - v0 = data_pts[s].co - v3 = data_pts[e].co - a = v0 * bernsteinPoly(3, 0, u) - b = v0 * bernsteinPoly(3, 1, u) - c = v3 * bernsteinPoly(3, 2, u) - d = v3 * bernsteinPoly(3, 3, u) - return (di - (a + b + c + d)) - - t1 = unitTangent(s, data_pts) - t2 = unitTangent(e, data_pts) - c11 = sum([A(i, 1, s, e, t1, t2) * A(i, 1, s, e, t1, t2) for i in range(s, e + 1)]) - c12 = sum([A(i, 1, s, e, t1, t2) * A(i, 2, s, e, t1, t2) for i in range(s, e + 1)]) - c21 = c12 - c22 = sum([A(i, 2, s, e, t1, t2) * A(i, 2, s, e, t1, t2) for i in range(s, e + 1)]) - - x1 = sum([xComponent(i, s, e) * A(i, 1, s, e, t1, t2) for i in range(s, e + 1)]) - x2 = sum([xComponent(i, s, e) * A(i, 2, s, e, t1, t2) for i in range(s, e + 1)]) - - # calculate Determinate of the 3 matrices - det_cc = c11 * c22 - c21 * c12 - det_cx = c11 * x2 - c12 * x1 - det_xc = x1 * c22 - x2 * c12 - - # if matrix is not homogenous, fudge the data a bit - if det_cc == 0: - det_cc = 0.01 - - # alpha's are the correct offset for bezier handles - alpha0 = det_xc / det_cc # offset from right (first) point - alpha1 = det_cx / det_cc # offset from left (last) point - - sRightHandle = data_pts[s].co.copy() - sTangent = t1 * abs(alpha0) - sRightHandle += sTangent # position of first pt's handle - eLeftHandle = data_pts[e].co.copy() - eTangent = t2 * abs(alpha1) - eLeftHandle += eTangent # position of last pt's handle. - - # return a 4 member tuple representing the bezier - return (data_pts[s].co, - sRightHandle, - eLeftHandle, - data_pts[e].co) - - # convert 2 given data points into a cubic bezier. - # handles are offset along the tangent at - # a 3rd of the length between the points. - def fitSingleCubic2Pts(data_pts, s, e): - alpha0 = alpha1 = (data_pts[s].co - data_pts[e].co).length / 3 - - sRightHandle = data_pts[s].co.copy() - sTangent = unitTangent(s, data_pts) * abs(alpha0) - sRightHandle += sTangent # position of first pt's handle - eLeftHandle = data_pts[e].co.copy() - eTangent = unitTangent(e, data_pts) * abs(alpha1) - eLeftHandle += eTangent # position of last pt's handle. - - #return a 4 member tuple representing the bezier - return (data_pts[s].co, - sRightHandle, - eLeftHandle, - data_pts[e].co) - - #evaluate bezier, represented by a 4 member tuple (pts) at point t. - def bezierEval(pts, t): - sumVec = NdVector((0, 0, 0, 0, 0)) - for i in range(4): - sumVec += pts[i] * bernsteinPoly(3, i, t) - return sumVec - - #calculate the highest error between bezier and original data - #returns the distance and the index of the point where max error occurs. - def maxErrorAmount(data_pts, bez, s, e): - maxError = 0 - maxErrorPt = s - if e - s < 3: - return 0, None - for pt in data_pts[s:e + 1]: - bezVal = bezierEval(bez, pt.u) - normalize_error = pt.co.length - if normalize_error == 0: - normalize_error = 1 - tmpError = (pt.co - bezVal).length / normalize_error - if tmpError >= maxError: - maxError = tmpError - maxErrorPt = pt.index - return maxError, maxErrorPt - - #calculated bezier derivative at point t. - #That is, tangent of point t. - def getBezDerivative(bez, t): - n = len(bez) - 1 - sumVec = NdVector((0, 0, 0, 0, 0)) - for i in range(n - 1): - sumVec += (bez[i + 1] - bez[i]) * bernsteinPoly(n - 1, i, t) - return sumVec - - #use Newton-Raphson to find a better paramterization of datapoints, - #one that minimizes the distance (or error) - # between bezier and original data. - def newtonRaphson(data_pts, s, e, bez): - for pt in data_pts[s:e + 1]: - if pt.index == s: - pt.u = 0 - elif pt.index == e: - pt.u = 1 - else: - u = pt.u - qu = bezierEval(bez, pt.u) - qud = getBezDerivative(bez, u) - #we wish to minimize f(u), - #the squared distance between curve and data - fu = (qu - pt.co).length ** 2 - fud = (2 * (qu.x - pt.co.x) * (qud.x)) - (2 * (qu.y - pt.co.y) * (qud.y)) - if fud == 0: - fu = 0 - fud = 1 - pt.u = pt.u - (fu / fud) - - #Create data_pts, a list of dataPoint type, each is assigned index i, and an NdVector - def createDataPts(curveGroup, group_mode): - data_pts = [] - if group_mode: - print([x.data_path for x in curveGroup]) - for i in range(len(curveGroup[0].keyframe_points)): - x = curveGroup[0].keyframe_points[i].co.x - y1 = curveGroup[0].keyframe_points[i].co.y - y2 = curveGroup[1].keyframe_points[i].co.y - y3 = curveGroup[2].keyframe_points[i].co.y - y4 = 0 - if len(curveGroup) == 4: - y4 = curveGroup[3].keyframe_points[i].co.y - data_pts.append(dataPoint(i, NdVector((x, y1, y2, y3, y4)))) - else: - for i in range(len(curveGroup.keyframe_points)): - x = curveGroup.keyframe_points[i].co.x - y1 = curveGroup.keyframe_points[i].co.y - y2 = 0 - y3 = 0 - y4 = 0 - data_pts.append(dataPoint(i, NdVector((x, y1, y2, y3, y4)))) - return data_pts - - #Recursively fit cubic beziers to the data_pts between s and e - def fitCubic(data_pts, s, e): - # if there are less than 3 points, fit a single basic bezier - if e - s < 3: - bez = fitSingleCubic2Pts(data_pts, s, e) - else: - #if there are more, parameterize the points - # and fit a single cubic bezier - chordLength(data_pts, s, e) - bez = fitSingleCubic(data_pts, s, e) - - #calculate max error and point where it occurs - maxError, maxErrorPt = maxErrorAmount(data_pts, bez, s, e) - #if error is small enough, reparameterization might be enough - if maxError < reparaError and maxError > error: - for i in range(maxIterations): - newtonRaphson(data_pts, s, e, bez) - if e - s < 3: - bez = fitSingleCubic2Pts(data_pts, s, e) - else: - bez = fitSingleCubic(data_pts, s, e) - - #recalculate max error and point where it occurs - maxError, maxErrorPt = maxErrorAmount(data_pts, bez, s, e) - - #repara wasn't enough, we need 2 beziers for this range. - #Split the bezier at point of maximum error - if maxError > error: - fitCubic(data_pts, s, maxErrorPt) - fitCubic(data_pts, maxErrorPt, e) - else: - #error is small enough, return the beziers. - beziers.append(bez) - return - - # deletes the sampled points and creates beziers. - def createNewCurves(curveGroup, beziers, group_mode): - #remove all existing data points - if group_mode: - for fcurve in curveGroup: - for i in range(len(fcurve.keyframe_points) - 1, 0, -1): - fcurve.keyframe_points.remove(fcurve.keyframe_points[i]) - else: - fcurve = curveGroup - for i in range(len(fcurve.keyframe_points) - 1, 0, -1): - fcurve.keyframe_points.remove(fcurve.keyframe_points[i]) - - #insert the calculated beziers to blender data.\ - if group_mode: - for fullbez in beziers: - for i, fcurve in enumerate(curveGroup): - bez = [Vector((vec[0], vec[i + 1])) for vec in fullbez] - newKey = fcurve.keyframe_points.insert(frame=bez[0].x, value=bez[0].y) - newKey.handle_right = (bez[1].x, bez[1].y) - - newKey = fcurve.keyframe_points.insert(frame=bez[3].x, value=bez[3].y) - newKey.handle_left = (bez[2].x, bez[2].y) - else: - for bez in beziers: - for vec in bez: - vec.resize_2d() - newKey = fcurve.keyframe_points.insert(frame=bez[0].x, value=bez[0].y) - newKey.handle_right = (bez[1].x, bez[1].y) - - newKey = fcurve.keyframe_points.insert(frame=bez[3].x, value=bez[3].y) - newKey.handle_left = (bez[2].x, bez[2].y) - - # indices are detached from data point's frame (x) value and - # stored in the dataPoint object, represent a range - - data_pts = createDataPts(curveGroup, group_mode) - - s = 0 # start - e = len(data_pts) - 1 # end - - beziers = [] - - #begin the recursive fitting algorithm. - fitCubic(data_pts, s, e) - #remove old Fcurves and insert the new ones - createNewCurves(curveGroup, beziers, group_mode) - - -#Main function of simplification, which called by Operator -#IN: -# sel_opt- either "sel" (selected) or "all" for which curves to effect -# error- maximum error allowed, in fraction (20% = 0.0020, which is the default), -# i.e. divide by 10000 from percentage wanted. -# group_mode- boolean, to analyze each curve seperately or in groups, -# where a group is all curves that effect the same property/RNA path -def fcurves_simplify(context, obj, sel_opt="all", error=0.002, group_mode=True): - # main vars - fcurves = obj.animation_data.action.fcurves - - if sel_opt == "sel": - sel_fcurves = [fcurve for fcurve in fcurves if fcurve.select] - else: - sel_fcurves = fcurves[:] - - #Error threshold for Newton Raphson reparamatizing - reparaError = error * 32 - maxIterations = 16 - - if group_mode: - fcurveDict = {} - #this loop sorts all the fcurves into groups of 3 or 4, - #based on their RNA Data path, which corresponds to - #which property they effect - for curve in sel_fcurves: - if curve.data_path in fcurveDict: # if this bone has been added, append the curve to its list - fcurveDict[curve.data_path].append(curve) - else: - fcurveDict[curve.data_path] = [curve] # new bone, add a new dict value with this first curve - fcurveGroups = fcurveDict.values() - else: - fcurveGroups = sel_fcurves - - if error > 0.00000: - #simplify every selected curve. - totalt = 0 - for i, fcurveGroup in enumerate(fcurveGroups): - print("Processing curve " + str(i + 1) + "/" + str(len(fcurveGroups))) - t = time.clock() - simplifyCurves(fcurveGroup, error, reparaError, maxIterations, group_mode) - t = time.clock() - t - print(str(t)[:5] + " seconds to process last curve") - totalt += t - print(str(totalt)[:5] + " seconds, total time elapsed") - - return - - -# Implementation of non-linear median filter, with variable kernel size -# Double pass - one marks spikes, the other smooths them -# Expects sampled keyframes on everyframe -# IN: None. Performs the operations on the active_object's fcurves. Expects animation_data.action to exist! -# OUT: None. Fixes the fcurves "in-place". -def denoise_median(): - context = bpy.context - obj = context.active_object - fcurves = obj.animation_data.action.fcurves - medKernel = 1 # actually *2+1... since it this is offset - flagKernel = 4 - highThres = (flagKernel * 2) - 1 - lowThres = 0 - for fcurve in fcurves: - orgPts = fcurve.keyframe_points[:] - flaggedFrames = [] - # mark frames that are spikes by sorting a large kernel - for i in range(flagKernel, len(fcurve.keyframe_points) - flagKernel): - center = orgPts[i] - neighborhood = orgPts[i - flagKernel: i + flagKernel] - neighborhood.sort(key=lambda pt: pt.co[1]) - weight = neighborhood.index(center) - if weight >= highThres or weight <= lowThres: - flaggedFrames.append((i, center)) - # clean marked frames with a simple median filter - # averages all frames in the kernel equally, except center which has no weight - for i, pt in flaggedFrames: - newValue = 0 - sumWeights = 0 - neighborhood = [neighpt.co[1] for neighpt in orgPts[i - medKernel: i + medKernel + 1] if neighpt != pt] - newValue = sum(neighborhood) / len(neighborhood) - pt.co[1] = newValue - return - - -# Recieves armature, and rotations all bones by 90 degrees along the X axis -# This fixes the common axis issue BVH files have when importing. -# IN: Armature (bpy.types.Armature) -def rotate_fix_armature(arm_data): - global_matrix = Matrix.Rotation(radians(90), 4, "X") - bpy.ops.object.mode_set(mode='EDIT', toggle=False) - #disconnect all bones for ease of global rotation - connectedBones = [] - for bone in arm_data.edit_bones: - if bone.use_connect: - connectedBones.append(bone.name) - bone.use_connect = False - - #rotate all the bones around their center - for bone in arm_data.edit_bones: - bone.transform(global_matrix) - - #reconnect the bones - for bone in connectedBones: - arm_data.edit_bones[bone].use_connect = True - bpy.ops.object.mode_set(mode='OBJECT', toggle=False) - - -#Roughly scales the performer armature to match the enduser armature -#IN: perfromer_obj, enduser_obj, Blender objects whose .data is an armature. -def scale_fix_armature(performer_obj, enduser_obj): - perf_bones = performer_obj.data.bones - end_bones = enduser_obj.data.bones - - def calculateBoundingRadius(bones): - center = Vector() - for bone in bones: - center += bone.head_local - center /= len(bones) - radius = 0 - for bone in bones: - dist = (bone.head_local - center).length - if dist > radius: - radius = dist - return radius - - perf_rad = calculateBoundingRadius(performer_obj.data.bones) - end_rad = calculateBoundingRadius(enduser_obj.data.bones) - #end_avg = enduser_obj.dimensions - factor = end_rad / perf_rad * 1.2 - performer_obj.scale *= factor - - -#Guess Mapping -#Given a performer and enduser armature, attempts to guess the hiearchy mapping -def guessMapping(performer_obj, enduser_obj): - perf_bones = performer_obj.data.bones - end_bones = enduser_obj.data.bones - - root = perf_bones[0] - - def findBoneSide(bone): - if "Left" in bone: - return "Left", bone.replace("Left", "").lower().replace(".", "") - if "Right" in bone: - return "Right", bone.replace("Right", "").lower().replace(".", "") - if "L" in bone: - return "Left", bone.replace("Left", "").lower().replace(".", "") - if "R" in bone: - return "Right", bone.replace("Right", "").lower().replace(".", "") - return "", bone - - def nameMatch(bone_a, bone_b): - # nameMatch - recieves two strings, returns 2 if they are relatively the same, 1 if they are the same but R and L and 0 if no match at all - side_a, noside_a = findBoneSide(bone_a) - side_b, noside_b = findBoneSide(bone_b) - if side_a == side_b: - if noside_a in noside_b or noside_b in noside_a: - return 2 - else: - if noside_a in noside_b or noside_b in noside_a: - return 1 - return 0 - - def guessSingleMapping(perf_bone): - possible_bones = [end_bones[0]] - - while possible_bones: - for end_bone in possible_bones: - match = nameMatch(perf_bone.name, end_bone.name) - if match == 2 and not perf_bone.map: - perf_bone.map = end_bone.name - #~ elif match == 1 and not perf_bone.map: - #~ oppo = perf_bones[oppositeBone(perf_bone)].map - # if oppo: - # perf_bone = oppo - newPossibleBones = [] - for end_bone in possible_bones: - newPossibleBones += list(end_bone.children) - possible_bones = newPossibleBones - - for child in perf_bone.children: - guessSingleMapping(child) - - guessSingleMapping(root) - - -# Creates limit rotation constraints on the enduser armature based on range of motion (max min of fcurves) of the performer. -# IN: context (bpy.context, etc.), and 2 blender objects which are armatures -# OUT: creates the limit constraints. -def limit_dof(context, performer_obj, enduser_obj): - limitDict = {} - perf_bones = [bone for bone in performer_obj.pose.bones if bone.bone.map] - c_frame = context.scene.frame_current - for bone in perf_bones: - limitDict[bone.bone.map] = [1000, 1000, 1000, -1000, -1000, -1000] - for t in range(context.scene.frame_start, context.scene.frame_end): - context.scene.frame_set(t) - for bone in perf_bones: - end_bone = enduser_obj.pose.bones[bone.bone.map] - bake_matrix = bone.matrix - rest_matrix = end_bone.bone.matrix_local - - if end_bone.parent and end_bone.bone.use_inherit_rotation: - srcParent = bone.parent - parent_mat = srcParent.matrix - parent_rest = end_bone.parent.bone.matrix_local - parent_rest_inv = parent_rest.inverted() - parent_mat_inv = parent_mat.inverted() - bake_matrix = parent_mat_inv * bake_matrix - rest_matrix = parent_rest_inv * rest_matrix - - rest_matrix_inv = rest_matrix.inverted() - bake_matrix = rest_matrix_inv * bake_matrix - - mat = bake_matrix - euler = mat.to_euler() - limitDict[bone.bone.map][0] = min(limitDict[bone.bone.map][0], euler.x) - limitDict[bone.bone.map][1] = min(limitDict[bone.bone.map][1], euler.y) - limitDict[bone.bone.map][2] = min(limitDict[bone.bone.map][2], euler.z) - limitDict[bone.bone.map][3] = max(limitDict[bone.bone.map][3], euler.x) - limitDict[bone.bone.map][4] = max(limitDict[bone.bone.map][4], euler.y) - limitDict[bone.bone.map][5] = max(limitDict[bone.bone.map][5], euler.z) - for bone in enduser_obj.pose.bones: - existingConstraint = [constraint for constraint in bone.constraints if constraint.name == "DOF Limitation"] - if existingConstraint: - bone.constraints.remove(existingConstraint[0]) - end_bones = [bone for bone in enduser_obj.pose.bones if bone.name in limitDict.keys()] - for bone in end_bones: - #~ if not bone.is_in_ik_chain: - newCons = bone.constraints.new("LIMIT_ROTATION") - newCons.name = "DOF Limitation" - newCons.owner_space = "LOCAL" - newCons.min_x, newCons.min_y, newCons.min_z, newCons.max_x, newCons.max_y, newCons.max_z = limitDict[bone.name] - newCons.use_limit_x = True - newCons.use_limit_y = True - newCons.use_limit_z = True - context.scene.frame_set(c_frame) - - -# Removes the constraints that were added by limit_dof on the enduser_obj -def limit_dof_toggle_off(context, enduser_obj): - for bone in enduser_obj.pose.bones: - existingConstraint = [constraint for constraint in bone.constraints if constraint.name == "DOF Limitation"] - if existingConstraint: - bone.constraints.remove(existingConstraint[0]) - - -# Reparameterizes a blender path via keyframing it's eval_time to match a stride_object's forward velocity. -# IN: Context, stride object (blender object with location keyframes), path object. -def path_editing(context, stride_obj, path): - y_fcurve = [fcurve for fcurve in stride_obj.animation_data.action.fcurves if fcurve.data_path == "location"][1] - s, e = context.scene.frame_start, context.scene.frame_end # y_fcurve.range() - s = int(s) - e = int(e) - y_s = y_fcurve.evaluate(s) - y_e = y_fcurve.evaluate(e) - direction = (y_e - y_s) / abs(y_e - y_s) - existing_cons = [constraint for constraint in stride_obj.constraints if constraint.type == "FOLLOW_PATH"] - for cons in existing_cons: - stride_obj.constraints.remove(cons) - path_cons = stride_obj.constraints.new("FOLLOW_PATH") - if direction < 0: - path_cons.forward_axis = "TRACK_NEGATIVE_Y" - else: - path_cons.forward_axis = "FORWARD_Y" - path_cons.target = path - path_cons.use_curve_follow = True - path.data.path_duration = e - s - try: - path.data.animation_data.action.fcurves - except AttributeError: - path.data.keyframe_insert("eval_time", frame=0) - eval_time_fcurve = [fcurve for fcurve in path.data.animation_data.action.fcurves if fcurve.data_path == "eval_time"] - eval_time_fcurve = eval_time_fcurve[0] - totalLength = 0 - parameterization = {} - print("evaluating curve") - for t in range(s, e - 1): - if s == t: - chordLength = 0 - else: - chordLength = (y_fcurve.evaluate(t) - y_fcurve.evaluate(t + 1)) - totalLength += chordLength - parameterization[t] = totalLength - for t in range(s + 1, e - 1): - if totalLength == 0: - print("no forward motion") - parameterization[t] /= totalLength - parameterization[t] *= e - s - parameterization[e] = e - s - for t in parameterization.keys(): - eval_time_fcurve.keyframe_points.insert(frame=t, value=parameterization[t]) - y_fcurve.mute = True - print("finished path editing") - - -#Animation Stitching -#Stitches two retargeted animations together via NLA settings. -#IN: enduser_obj, a blender armature that has had two retargets applied. -def anim_stitch(context, enduser_obj): - stitch_settings = enduser_obj.data.stitch_settings - action_1 = stitch_settings.first_action - action_2 = stitch_settings.second_action - if stitch_settings.stick_bone != "": - selected_bone = enduser_obj.pose.bones[stitch_settings.stick_bone] - else: - selected_bone = enduser_obj.pose.bones[0] - scene = context.scene - TrackNamesA = enduser_obj.data.mocapNLATracks[action_1] - TrackNamesB = enduser_obj.data.mocapNLATracks[action_2] - enduser_obj.data.active_mocap = action_1 - anim_data = enduser_obj.animation_data - # add tracks for action 2 - mocapAction = bpy.data.actions[TrackNamesB.base_track] - mocapTrack = anim_data.nla_tracks.new() - mocapTrack.name = TrackNamesB.base_track - mocapStrip = mocapTrack.strips.new(TrackNamesB.base_track, stitch_settings.blend_frame, mocapAction) - mocapStrip.extrapolation = "HOLD_FORWARD" - mocapStrip.blend_in = stitch_settings.blend_amount - mocapStrip.action_frame_start += stitch_settings.second_offset - mocapStrip.action_frame_end += stitch_settings.second_offset - constraintTrack = anim_data.nla_tracks.new() - constraintTrack.name = TrackNamesB.auto_fix_track - constraintAction = bpy.data.actions[TrackNamesB.auto_fix_track] - constraintStrip = constraintTrack.strips.new(TrackNamesB.auto_fix_track, stitch_settings.blend_frame, constraintAction) - constraintStrip.extrapolation = "HOLD_FORWARD" - constraintStrip.blend_in = stitch_settings.blend_amount - userTrack = anim_data.nla_tracks.new() - userTrack.name = TrackNamesB.manual_fix_track - userAction = bpy.data.actions[TrackNamesB.manual_fix_track] - userStrip = userTrack.strips.new(TrackNamesB.manual_fix_track, stitch_settings.blend_frame, userAction) - userStrip.extrapolation = "HOLD_FORWARD" - userStrip.blend_in = stitch_settings.blend_amount - #stride bone - if enduser_obj.parent: - if enduser_obj.parent.name == "stride_bone": - stride_bone = enduser_obj.parent - stride_anim_data = stride_bone.animation_data - stride_anim_data.use_nla = True - stride_anim_data.action = None - for track in stride_anim_data.nla_tracks: - stride_anim_data.nla_tracks.remove(track) - actionATrack = stride_anim_data.nla_tracks.new() - actionATrack.name = TrackNamesA.stride_action - actionAStrip = actionATrack.strips.new(TrackNamesA.stride_action, 0, bpy.data.actions[TrackNamesA.stride_action]) - actionAStrip.extrapolation = "NOTHING" - actionBTrack = stride_anim_data.nla_tracks.new() - actionBTrack.name = TrackNamesB.stride_action - actionBStrip = actionBTrack.strips.new(TrackNamesB.stride_action, stitch_settings.blend_frame, bpy.data.actions[TrackNamesB.stride_action]) - actionBStrip.action_frame_start += stitch_settings.second_offset - actionBStrip.action_frame_end += stitch_settings.second_offset - actionBStrip.blend_in = stitch_settings.blend_amount - actionBStrip.extrapolation = "NOTHING" - #we need to change the stride_bone's action to add the offset - scene.frame_set(stitch_settings.blend_frame - 1) - desired_pos = (selected_bone.matrix.to_translation() * enduser_obj.matrix_world) - scene.frame_set(stitch_settings.blend_frame) - actual_pos = (selected_bone.matrix.to_translation() * enduser_obj.matrix_world) - offset = actual_pos - desired_pos - - for i, fcurve in enumerate([fcurve for fcurve in bpy.data.actions[TrackNamesB.stride_action].fcurves if fcurve.data_path == "location"]): - print(offset[i], i, fcurve.array_index) - for pt in fcurve.keyframe_points: - pt.co.y -= offset[i] - pt.handle_left.y -= offset[i] - pt.handle_right.y -= offset[i] - - -#Guesses setting for animation stitching via Cross Correlation -def guess_anim_stitch(context, enduser_obj): - stitch_settings = enduser_obj.data.stitch_settings - action_1 = stitch_settings.first_action - action_2 = stitch_settings.second_action - TrackNamesA = enduser_obj.data.mocapNLATracks[action_1] - TrackNamesB = enduser_obj.data.mocapNLATracks[action_2] - mocapA = bpy.data.actions[TrackNamesA.base_track] - mocapB = bpy.data.actions[TrackNamesB.base_track] - curvesA = mocapA.fcurves - curvesB = mocapB.fcurves - flm, s, data = crossCorrelationMatch(curvesA, curvesB, 10) - print("Guessed the following for start and offset: ", s, flm) - enduser_obj.data.stitch_settings.blend_frame = flm - enduser_obj.data.stitch_settings.second_offset = s diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py deleted file mode 100644 index 67e8c7da55d..00000000000 --- a/release/scripts/modules/retarget.py +++ /dev/null @@ -1,559 +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 ##### - -# - -import bpy -from mathutils import * -from math import radians, acos, pi -from bl_operators import nla - - -def hasIKConstraint(pose_bone): - #utility function / predicate, returns True if given bone has IK constraint - ik = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"] - if ik: - return ik[0] - else: - return False - - -def createDictionary(perf_arm, end_arm): - # clear any old data - for end_bone in end_arm.bones: - for mapping in end_bone.reverseMap: - end_bone.reverseMap.remove(0) - - for perf_bone in perf_arm.bones: - #find its match and add perf_bone to the match's mapping - if perf_bone.map: - end_bone = end_arm.bones[perf_bone.map] - newMap = end_bone.reverseMap.add() - newMap.name = perf_bone.name - end_bone.foot = perf_bone.foot - - #root is the root of the enduser - root = end_arm.bones[0].name - feetBones = [bone.name for bone in perf_arm.bones if bone.foot] - return feetBones, root - - -def loadMapping(perf_arm, end_arm): - for end_bone in end_arm.bones: - #find its match and add perf_bone to the match's mapping - if end_bone.reverseMap: - for perf_bone in end_bone.reverseMap: - perf_arm.bones[perf_bone.name].map = end_bone.name - -#creation of intermediate armature -# the intermediate armature has the hiearchy of the end user, -# does not have rotation inheritence -# and bone roll is identical to the performer -# its purpose is to copy over the rotations -# easily while concentrating on the hierarchy changes - - -def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene, step): - #creates and keyframes an empty with its location - #the original position of the tail bone - #useful for storing the important data in the original motion - #i.e. using this empty to IK the chain to that pos / DEBUG - - #Simple 1to1 retarget of a bone - def singleBoneRetarget(inter_bone, perf_bone): - perf_world_rotation = perf_bone.matrix - inter_world_base_rotation = inter_bone.bone.matrix_local - inter_world_base_inv = inter_world_base_rotation.inverted() - bake_matrix = (inter_world_base_inv.to_3x3() * perf_world_rotation.to_3x3()) - return bake_matrix.to_4x4() - - #uses 1to1 and interpolation/averaging to match many to 1 retarget - def manyPerfToSingleInterRetarget(inter_bone, performer_bones_s): - retarget_matrices = [singleBoneRetarget(inter_bone, perf_bone) for perf_bone in performer_bones_s] - lerp_matrix = Matrix() - for i in range(len(retarget_matrices) - 1): - first_mat = retarget_matrices[i] - next_mat = retarget_matrices[i + 1] - lerp_matrix = first_mat.lerp(next_mat, 0.5) - return lerp_matrix - - #determines the type of hierachy change needed and calls the - #right function - def retargetPerfToInter(inter_bone): - if inter_bone.bone.reverseMap: - perf_bone_name = inter_bone.bone.reverseMap - # 1 to many not supported yet - # then its either a many to 1 or 1 to 1 - if len(perf_bone_name) > 1: - performer_bones_s = [performer_bones[map.name] for map in perf_bone_name] - #we need to map several performance bone to a single - inter_bone.matrix_basis = manyPerfToSingleInterRetarget(inter_bone, performer_bones_s) - else: - perf_bone = performer_bones[perf_bone_name[0].name] - inter_bone.matrix_basis = singleBoneRetarget(inter_bone, perf_bone) - #Some bones have incorrect roll on the source armature, and need to be marked for fixing - if inter_bone.bone.twistFix: - inter_bone.matrix_basis *= Matrix.Rotation(radians(180), 4, "Y") - rot_mode = inter_bone.rotation_mode - if rot_mode == "QUATERNION": - inter_bone.keyframe_insert("rotation_quaternion") - elif rot_mode == "AXIS_ANGLE": - inter_bone.keyframe_insert("rotation_axis_angle") - else: - inter_bone.keyframe_insert("rotation_euler") - - #creates the intermediate armature object - inter_obj = enduser_obj.copy() - inter_obj.data = inter_obj.data.copy() # duplicate data - bpy.context.scene.objects.link(inter_obj) - inter_obj.name = "intermediate" - bpy.context.scene.objects.active = inter_obj - bpy.ops.object.mode_set(mode='EDIT') - #add some temporary connecting bones in case end user bones are not connected to their parents - rollDict = {} - print("creating temp bones") - for bone in inter_obj.data.edit_bones: - if not bone.use_connect and bone.parent: - if inter_obj.data.bones[bone.parent.name].reverseMap or inter_obj.data.bones[bone.name].reverseMap: - newBone = inter_obj.data.edit_bones.new("Temp") - newBone.head = bone.parent.tail - newBone.tail = bone.head - newBone.parent = bone.parent - bone.parent = newBone - bone.use_connect = True - newBone.use_connect = True - rollDict[bone.name] = bone.roll - bone.roll = 0 - #resets roll - print("retargeting to intermediate") - bpy.ops.object.mode_set(mode="OBJECT") - inter_obj.data.name = "inter_arm" - inter_arm = inter_obj.data - performer_bones = performer_obj.pose.bones - inter_bones = inter_obj.pose.bones - #clears inheritance - for inter_bone in inter_bones: - if inter_bone.bone.reverseMap: - inter_bone.bone.use_inherit_rotation = False - else: - inter_bone.bone.use_inherit_rotation = True - - for t in range(s_frame, e_frame, step): - if (t - s_frame) % 10 == 0: - print("First pass: retargeting frame {0}/{1}".format(t, e_frame - s_frame)) - scene.frame_set(t) - for bone in inter_bones: - retargetPerfToInter(bone) - - return inter_obj - -# this procedure copies the rotations over from the intermediate -# armature to the end user one. -# As the hierarchies are 1 to 1, this is a simple matter of -# copying the rotation, while keeping in mind bone roll, parenting, etc. -# TODO: Control Bones: If a certain bone is constrained in a way -# that its rotation is determined by another (a control bone) -# We should determine the right pos of the control bone. -# Scale: ? Should work but needs testing. - - -def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene, step): - inter_bones = inter_obj.pose.bones - end_bones = enduser_obj.pose.bones - - #Basic "visual baking" function, for transfering rotations from intermediate to end user - def bakeTransform(end_bone): - src_bone = inter_bones[end_bone.name] - trg_bone = end_bone - bake_matrix = src_bone.matrix - rest_matrix = trg_bone.bone.matrix_local - - if trg_bone.parent and trg_bone.bone.use_inherit_rotation: - srcParent = src_bone.parent - if "Temp" in srcParent.name: - srcParent = srcParent.parent - parent_mat = srcParent.matrix - parent_rest = trg_bone.parent.bone.matrix_local - parent_rest_inv = parent_rest.inverted() - parent_mat_inv = parent_mat.inverted() - bake_matrix = parent_mat_inv * bake_matrix - rest_matrix = parent_rest_inv * rest_matrix - - rest_matrix_inv = rest_matrix.inverted() - bake_matrix = rest_matrix_inv * bake_matrix - end_bone.matrix_basis = bake_matrix - rot_mode = end_bone.rotation_mode - if rot_mode == "QUATERNION": - end_bone.keyframe_insert("rotation_quaternion") - elif rot_mode == "AXIS_ANGLE": - end_bone.keyframe_insert("rotation_axis_angle") - else: - end_bone.keyframe_insert("rotation_euler") - if not end_bone.bone.use_connect: - end_bone.keyframe_insert("location") - - for bone in end_bone.children: - bakeTransform(bone) - - for t in range(s_frame, e_frame, step): - if (t - s_frame) % 10 == 0: - print("Second pass: retargeting frame {0}/{1}".format(t, e_frame - s_frame)) - scene.frame_set(t) - end_bone = end_bones[root] - end_bone.location = Vector((0, 0, 0)) - end_bone.keyframe_insert("location") - bakeTransform(end_bone) - -#recieves the performer feet bones as a variable -# by "feet" I mean those bones that have plants -# (they don't move, despite root moving) somewhere in the animation. - - -def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame, scene, enduser_obj_mat): - - perf_bones = performer_obj.pose.bones - end_bones = enduser_obj.pose.bones - - perfRoot = perf_bones[0].name - endFeet = [perf_bones[perfBone].bone.map for perfBone in perfFeet] - locDictKeys = perfFeet + endFeet + [perfRoot] - - def tailLoc(bone): - return bone.center + (bone.vector / 2) - - #Step 1 - we create a dict that contains these keys: - #(Performer) Hips, Feet - #(End user) Feet - # where the values are their world position on each frame in range (s,e) - - locDict = {} - for key in locDictKeys: - locDict[key] = [] - - for t in range(scene.frame_start, scene.frame_end): - scene.frame_set(t) - for bone in perfFeet: - locDict[bone].append(tailLoc(perf_bones[bone])) - locDict[perfRoot].append(tailLoc(perf_bones[perfRoot])) - for bone in endFeet: - locDict[bone].append(tailLoc(end_bones[bone])) - - # now we take our locDict and analyze it. - # we need to derive all chains - - def locDeriv(key, t): - graph = locDict[key] - return graph[t + 1] - graph[t] - - # now find the plant frames, where perfFeet don't move much - - linearAvg = [] - - for key in perfFeet: - for i in range(len(locDict[key]) - 1): - v = locDeriv(key, i) - if (v.length < 0.1): - hipV = locDeriv(perfRoot, i) - endV = locDeriv(perf_bones[key].bone.map, i) - #this is a plant frame. - #lets see what the original hip delta is, and the corresponding - #end bone's delta - if endV.length != 0: - linearAvg.append(hipV.length / endV.length) - - action_name = performer_obj.animation_data.action.name - #is there a stride_bone? - if "stride_bone" in bpy.data.objects: - stride_action = bpy.data.actions.new("Stride Bone " + action_name) - stride_action.use_fake_user = True - stride_bone = enduser_obj.parent - stride_bone.animation_data.action = stride_action - else: - bpy.ops.object.add() - stride_bone = bpy.context.active_object - stride_bone.name = "stride_bone" - print(stride_bone) - stride_bone.location = enduser_obj_mat.to_translation() - print(linearAvg) - if linearAvg: - #determine the average change in scale needed - avg = sum(linearAvg) / len(linearAvg) - scene.frame_set(s_frame) - initialPos = (tailLoc(perf_bones[perfRoot]) / avg) - for t in range(s_frame, e_frame): - scene.frame_set(t) - #calculate the new position, by dividing by the found ratio between performer and enduser - newTranslation = (tailLoc(perf_bones[perfRoot]) / avg) - stride_bone.location = enduser_obj_mat * (newTranslation - initialPos) - stride_bone.keyframe_insert("location") - else: - stride_bone.keyframe_insert("location") - stride_bone.animation_data.action.name = ("Stride Bone " + action_name) - - return stride_bone - - -def IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene, step): - bpy.ops.object.select_name(name=enduser_obj.name, extend=False) - end_bones = enduser_obj.pose.bones - for pose_bone in end_bones: - ik_constraint = hasIKConstraint(pose_bone) - if ik_constraint: - target_is_bone = False - # set constraint target to corresponding empty if targetless, - # if not, keyframe current target to corresponding empty - perf_bone = pose_bone.bone.reverseMap[-1].name - bpy.ops.object.mode_set(mode='EDIT') - orgLocTrg = originalLocationTarget(pose_bone, enduser_obj) - bpy.ops.object.mode_set(mode='OBJECT') - if not ik_constraint.target: - ik_constraint.target = enduser_obj - ik_constraint.subtarget = pose_bone.name + "IK" - target = orgLocTrg - - # There is a target now - if ik_constraint.subtarget: - target = ik_constraint.target.pose.bones[ik_constraint.subtarget] - target.bone.use_local_location = False - target_is_bone = True - else: - target = ik_constraint.target - - # bake the correct locations for the ik target bones - for t in range(s_frame, e_frame, step): - scene.frame_set(t) - if target_is_bone: - final_loc = pose_bone.tail - target.bone.matrix_local.to_translation() - else: - final_loc = pose_bone.tail - target.location = final_loc - target.keyframe_insert("location") - ik_constraint.mute = False - scene.frame_set(s_frame) - bpy.ops.object.mode_set(mode='OBJECT') - - -def turnOffIK(enduser_obj): - end_bones = enduser_obj.pose.bones - for pose_bone in end_bones: - ik_constraint = hasIKConstraint(pose_bone) - if ik_constraint: - ik_constraint.mute = True - - -#copy the object matrixes and clear them (to be reinserted later) -def cleanAndStoreObjMat(performer_obj, enduser_obj): - perf_obj_mat = performer_obj.matrix_world.copy() - enduser_obj_mat = enduser_obj.matrix_world.copy() - zero_mat = Matrix() - performer_obj.matrix_world = zero_mat - enduser_obj.matrix_world = zero_mat - return perf_obj_mat, enduser_obj_mat - - -#restore the object matrixes after parenting the auto generated IK empties -def restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone, scene, s_frame): - pose_bones = enduser_obj.pose.bones - for pose_bone in pose_bones: - if pose_bone.name + "Org" in bpy.data.objects: - empty = bpy.data.objects[pose_bone.name + "Org"] - empty.parent = stride_bone - performer_obj.matrix_world = perf_obj_mat - enduser_obj.parent = stride_bone - scene.frame_set(s_frame) - enduser_obj_mat = enduser_obj_mat.to_3x3().to_4x4() * Matrix.Translation(stride_bone.matrix_world.to_translation()) - enduser_obj.matrix_world = enduser_obj_mat - - -#create (or return if exists) the related IK empty to the bone -def originalLocationTarget(end_bone, enduser_obj): - if not end_bone.name + "IK" in enduser_obj.data.bones: - newBone = enduser_obj.data.edit_bones.new(end_bone.name + "IK") - newBone.head = end_bone.tail - newBone.tail = end_bone.tail + Vector((0, 0.1, 0)) - else: - newBone = enduser_obj.pose.bones[end_bone.name + "IK"] - return newBone - - -#create the specified NLA setup for base animation, constraints and tweak layer. -def NLASystemInitialize(enduser_arm, context): - enduser_obj = context.active_object - NLATracks = enduser_arm.mocapNLATracks[enduser_obj.data.active_mocap] - name = NLATracks.name - anim_data = enduser_obj.animation_data - s_frame = 0 - print(name) - if ("Base " + name) in bpy.data.actions: - mocapAction = bpy.data.actions[("Base " + name)] - else: - print("That retargeted anim has no base action") - anim_data.use_nla = True - for track in anim_data.nla_tracks: - anim_data.nla_tracks.remove(track) - mocapTrack = anim_data.nla_tracks.new() - mocapTrack.name = "Base " + name - NLATracks.base_track = mocapTrack.name - mocapStrip = mocapTrack.strips.new("Base " + name, s_frame, mocapAction) - constraintTrack = anim_data.nla_tracks.new() - constraintTrack.name = "Auto fixes " + name - NLATracks.auto_fix_track = constraintTrack.name - if ("Auto fixes " + name) in bpy.data.actions: - constraintAction = bpy.data.actions[("Auto fixes " + name)] - else: - constraintAction = bpy.data.actions.new("Auto fixes " + name) - constraintAction.use_fake_user = True - constraintStrip = constraintTrack.strips.new("Auto fixes " + name, s_frame, constraintAction) - constraintStrip.extrapolation = "NOTHING" - userTrack = anim_data.nla_tracks.new() - userTrack.name = "Manual fixes " + name - NLATracks.manual_fix_track = userTrack.name - if ("Manual fixes " + name) in bpy.data.actions: - userAction = bpy.data.actions[("Manual fixes " + name)] - else: - userAction = bpy.data.actions.new("Manual fixes " + name) - userAction.use_fake_user = True - userStrip = userTrack.strips.new("Manual fixes " + name, s_frame, userAction) - userStrip.extrapolation = "HOLD" - userStrip.blend_type = "ADD" - anim_data.nla_tracks.active = constraintTrack - anim_data.action_extrapolation = "NOTHING" - #set the stride_bone's action - if "stride_bone" in bpy.data.objects: - stride_bone = bpy.data.objects["stride_bone"] - if NLATracks.stride_action: - stride_bone.animation_data.action = bpy.data.actions[NLATracks.stride_action] - else: - NLATracks.stride_action = stride_bone.animation_data.action.name - stride_bone.animation_data.action.use_fake_user = True - anim_data.action = None - - -def preAdvancedRetargeting(performer_obj, enduser_obj): - createDictionary(performer_obj.data, enduser_obj.data) - bones = enduser_obj.pose.bones - map_bones = [bone for bone in bones if bone.bone.reverseMap] - perf_root = performer_obj.pose.bones[0].name - for bone in map_bones: - perf_bone = bone.bone.reverseMap[0].name - - cons = bone.constraints.new('COPY_ROTATION') - cons.name = "retargetTemp" - locks = bone.lock_rotation - cons.use_x = not locks[0] - cons.use_y = not locks[1] - cons.use_z = not locks[2] - cons.target = performer_obj - cons.subtarget = perf_bone - cons.target_space = 'WORLD' - cons.owner_space = 'WORLD' - - if (not bone.bone.use_connect) and (perf_bone != perf_root): - cons = bone.constraints.new('COPY_LOCATION') - cons.name = "retargetTemp" - cons.target = performer_obj - cons.subtarget = perf_bone - cons.use_x = True - cons.use_y = True - cons.use_z = True - cons.target_space = 'LOCAL' - cons.owner_space = 'LOCAL' - - -def prepareForBake(enduser_obj): - bones = enduser_obj.pose.bones - for bone in bones: - bone.bone.select = False - map_bones = [bone for bone in bones if bone.bone.reverseMap] - for bone in map_bones: - for cons in bone.constraints: - if "retargetTemp" in cons.name: - bone.bone.select = True - - -def cleanTempConstraints(enduser_obj): - bones = enduser_obj.pose.bones - map_bones = [bone for bone in bones if bone.bone.reverseMap] - for bone in map_bones: - for cons in bone.constraints: - if "retargetTemp" in cons.name: - bone.constraints.remove(cons) - - -#Main function that runs the retargeting sequence. -#If advanced == True, we assume constraint's were already created -def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): - perf_arm = performer_obj.data - end_arm = enduser_obj.data - advanced = end_arm.advancedRetarget - step = end_arm.frameStep - - try: - enduser_obj.animation_data.action = bpy.data.actions.new("temp") - enduser_obj.animation_data.action.use_fake_user = True - except: - print("no need to create new action") - - print("creating Dictionary") - feetBones, root = createDictionary(perf_arm, end_arm) - print("cleaning stuff up") - perf_obj_mat, enduser_obj_mat = cleanAndStoreObjMat(performer_obj, enduser_obj) - if not advanced: - turnOffIK(enduser_obj) - print("Creating intermediate armature (for first pass)") - inter_obj = createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene, step) - print("First pass: retargeting from intermediate to end user") - retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene, step) - else: - prepareForBake(enduser_obj) - print("Retargeting pose (Advanced Retarget)") - nla.bake(s_frame, e_frame, action=enduser_obj.animation_data.action, only_selected=True, do_pose=True, do_object=False, step=step) - name = performer_obj.animation_data.action.name - enduser_obj.animation_data.action.name = "Base " + name - print("Second pass: retargeting root translation and clean up") - stride_bone = copyTranslation(performer_obj, enduser_obj, feetBones, root, s_frame, e_frame, scene, enduser_obj_mat) - if not advanced: - IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene, step) - bpy.ops.object.select_name(name=stride_bone.name, extend=False) - restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone, scene, s_frame) - bpy.ops.object.mode_set(mode='OBJECT') - if not advanced: - bpy.ops.object.select_name(name=inter_obj.name, extend=False) - bpy.ops.object.delete() - else: - cleanTempConstraints(enduser_obj) - bpy.ops.object.select_name(name=enduser_obj.name, extend=False) - - if not name in [tracks.name for tracks in end_arm.mocapNLATracks]: - NLATracks = end_arm.mocapNLATracks.add() - NLATracks.name = name - else: - NLATracks = end_arm.mocapNLATracks[name] - end_arm.active_mocap = name - print("retargeting done!") - - -def isRigAdvanced(enduser_obj): - bones = enduser_obj.pose.bones - for bone in bones: - for constraint in bone.constraints: - if constraint.type != "IK": - return True - if enduser_obj.data.animation_data: - if enduser_obj.data.animation_data.drivers: - return True diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py deleted file mode 100644 index 3cb33776b0b..00000000000 --- a/release/scripts/startup/ui_mocap.py +++ /dev/null @@ -1,850 +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 ##### - -# - -import bpy - -from bpy.props import * -from bpy import * -import mocap_constraints -import retarget -import mocap_tools - -### reloads modules (for testing purposes only) -from imp import reload -reload(mocap_constraints) -reload(retarget) -reload(mocap_tools) - -from mocap_constraints import * - -# MocapConstraint class -# Defines MocapConstraint datatype, used to add and configute mocap constraints -# Attached to Armature data - - -class MocapConstraint(bpy.types.PropertyGroup): - name = bpy.props.StringProperty(name="Name", - default="Mocap Fix", - description="Name of Mocap Fix", - update=setConstraint) - constrained_bone = bpy.props.StringProperty(name="Bone", - default="", - description="Constrained Bone", - update=updateConstraintBoneType) - constrained_boneB = bpy.props.StringProperty(name="Bone (2)", - default="", - description="Other Constrained Bone (optional, depends on type)", - update=setConstraint) - s_frame = bpy.props.IntProperty(name="S", - default=0, - description="Start frame of Fix", - update=setConstraint) - e_frame = bpy.props.IntProperty(name="E", - default=100, - description="End frame of Fix", - update=setConstraint) - smooth_in = bpy.props.IntProperty(name="In", - default=10, - description="Amount of frames to smooth in", - update=setConstraint, - min=0) - smooth_out = bpy.props.IntProperty(name="Out", - default=10, - description="Amount of frames to smooth out", - update=setConstraint, - min=0) - targetMesh = bpy.props.StringProperty(name="Mesh", - default="", - description="Target of Fix - Mesh (optional, depends on type)", - update=setConstraint) - active = bpy.props.BoolProperty(name="Active", - default=True, - description="Fix is active", - update=setConstraint) - show_expanded = bpy.props.BoolProperty(name="Show Expanded", - default=True, - description="Fix is fully shown") - targetPoint = bpy.props.FloatVectorProperty(name="Point", size=3, - subtype="XYZ", default=(0.0, 0.0, 0.0), - description="Target of Fix - Point", - update=setConstraint) - targetDist = bpy.props.FloatProperty(name="Offset", - default=0.0, - description="Distance and Floor Fixes - Desired offset", - update=setConstraint) - targetSpace = bpy.props.EnumProperty( - items=[("WORLD", "World Space", "Evaluate target in global space"), - ("LOCAL", "Object space", "Evaluate target in object space"), - ("constrained_boneB", "Other Bone Space", "Evaluate target in specified other bone space")], - name="Space", - description="In which space should Point type target be evaluated", - update=setConstraint) - type = bpy.props.EnumProperty(name="Type of constraint", - items=[("point", "Maintain Position", "Bone is at a specific point"), - ("freeze", "Maintain Position at frame", "Bone does not move from location specified in target frame"), - ("floor", "Stay above", "Bone does not cross specified mesh object eg floor"), - ("distance", "Maintain distance", "Target bones maintained specified distance")], - description="Type of Fix", - update=updateConstraintBoneType) - real_constraint = bpy.props.StringProperty() - real_constraint_bone = bpy.props.StringProperty() - - -bpy.utils.register_class(MocapConstraint) - -bpy.types.Armature.mocap_constraints = bpy.props.CollectionProperty(type=MocapConstraint) - - -# Animation Stitch Settings, used for animation stitching of 2 retargeted animations. -class AnimationStitchSettings(bpy.types.PropertyGroup): - first_action = bpy.props.StringProperty(name="Action 1", - description="First action in stitch") - second_action = bpy.props.StringProperty(name="Action 2", - description="Second action in stitch") - blend_frame = bpy.props.IntProperty(name="Stitch frame", - description="Frame to locate stitch on") - blend_amount = bpy.props.IntProperty(name="Blend amount", - description="Size of blending transitiion, on both sides of the stitch", - default=10) - second_offset = bpy.props.IntProperty(name="Second offset", - description="Frame offset for 2nd animation, where it should start", - default=10) - stick_bone = bpy.props.StringProperty(name="Stick Bone", - description="Bone to freeze during transition", - default="") - -bpy.utils.register_class(AnimationStitchSettings) - - -# MocapNLA Tracks. Stores which tracks/actions are associated with each retargeted animation. -class MocapNLATracks(bpy.types.PropertyGroup): - name = bpy.props.StringProperty() - base_track = bpy.props.StringProperty() - auto_fix_track = bpy.props.StringProperty() - manual_fix_track = bpy.props.StringProperty() - stride_action = bpy.props.StringProperty() - -bpy.utils.register_class(MocapNLATracks) - - -#Update function for Advanced Retarget boolean variable. -def advancedRetargetToggle(self, context): - enduser_obj = context.active_object - performer_obj = [obj for obj in context.selected_objects if obj != enduser_obj] - if enduser_obj is None or len(performer_obj) != 1: - print("Need active and selected armatures") - return - else: - performer_obj = performer_obj[0] - if self.advancedRetarget: - retarget.preAdvancedRetargeting(performer_obj, enduser_obj) - else: - retarget.cleanTempConstraints(enduser_obj) - - -#Animation Stitch Settings Property -bpy.types.Armature.stitch_settings = bpy.props.PointerProperty(type=AnimationStitchSettings) -#Current/Active retargeted animation on the armature -bpy.types.Armature.active_mocap = bpy.props.StringProperty(update=retarget.NLASystemInitialize) -#Collection of retargeted animations and their NLA Tracks on the armature -bpy.types.Armature.mocapNLATracks = bpy.props.CollectionProperty(type=MocapNLATracks) -#Advanced retargeting boolean property -bpy.types.Armature.advancedRetarget = bpy.props.BoolProperty(default=False, update=advancedRetargetToggle) -#frame step - frequency of frames to retarget. Skipping is useful for previewing, faster work etc. -bpy.types.Armature.frameStep = smooth_out = bpy.props.IntProperty(name="Frame Skip", - default=1, - description="Amount of frames to skip - for previewing retargets quickly. 1 is fully sampled", - min=1) - - -def toggleIKBone(self, context): - #Update function for IK functionality. Is called when IK prop checkboxes are toggled. - if self.IKRetarget: - if not self.is_in_ik_chain: - print(self.name + " IK toggled ON!") - ik = self.constraints.new('IK') - #ik the whole chain up to the root, excluding - chainLen = 0 - for parent_bone in self.parent_recursive: - chainLen += 1 - if hasIKConstraint(parent_bone): - break - deformer_children = [child for child in parent_bone.children if child.bone.use_deform] - #~ if len(deformer_children) > 1: - #~ break - ik.chain_count = chainLen - for bone in self.parent_recursive: - if bone.is_in_ik_chain: - bone.IKRetarget = True - else: - print(self.name + " IK toggled OFF!") - cnstrn_bones = [] - newChainLength = [] - if hasIKConstraint(self): - cnstrn_bones = [self] - elif self.is_in_ik_chain: - cnstrn_bones = [child for child in self.children_recursive if hasIKConstraint(child)] - for cnstrn_bone in cnstrn_bones: - newChainLength.append(cnstrn_bone.parent_recursive.index(self) + 1) - if cnstrn_bones: - # remove constraint, and update IK retarget for all parents of cnstrn_bone up to chain_len - for i, cnstrn_bone in enumerate(cnstrn_bones): - print(cnstrn_bone.name) - if newChainLength: - ik = hasIKConstraint(cnstrn_bone) - ik.chain_count = newChainLength[i] - else: - ik = hasIKConstraint(cnstrn_bone) - cnstrn_bone.constraints.remove(ik) - cnstrn_bone.IKRetarget = False - for bone in cnstrn_bone.parent_recursive: - if not bone.is_in_ik_chain: - bone.IKRetarget = False - - -#MocapMap class for storing mapping on enduser performer, -# where a bone may be linked to more than one on the performer -class MocapMapping(bpy.types.PropertyGroup): - name = bpy.props.StringProperty() - -bpy.utils.register_class(MocapMapping) - -#string property for storing performer->enduser mapping -bpy.types.Bone.map = bpy.props.StringProperty() -#Collection Property for storing enduser->performer mapping -bpy.types.Bone.reverseMap = bpy.props.CollectionProperty(type=MocapMapping) -#Boolean property for storing foot bone toggle -bpy.types.Bone.foot = bpy.props.BoolProperty(name="Foot", - description="Marks this bone as a 'foot', which determines retargeted animation's translation", - default=False) -#Boolean property for storing if this bone is twisted along the y axis, -# which can happen due to various sources of performers -bpy.types.Bone.twistFix = bpy.props.BoolProperty(name="Twist Fix", - description="Fix Twist on this bone", - default=False) -#Boolean property for toggling ik retargeting for this bone -bpy.types.PoseBone.IKRetarget = bpy.props.BoolProperty(name="IK", - description="Toggles IK Retargeting method for given bone", - update=toggleIKBone, default=False) - - -def updateIKRetarget(): - # ensures that Blender constraints and IK properties are in sync - # currently runs when module is loaded, should run when scene is loaded - # or user adds a constraint to armature. Will be corrected in the future, - # once python callbacks are implemented - for obj in bpy.data.objects: - if obj.pose: - bones = obj.pose.bones - for pose_bone in bones: - if pose_bone.is_in_ik_chain or hasIKConstraint(pose_bone): - pose_bone.IKRetarget = True - else: - pose_bone.IKRetarget = False - -updateIKRetarget() - - -class MocapPanel(bpy.types.Panel): - # Motion capture retargeting panel - bl_label = "Mocap tools" - bl_space_type = "PROPERTIES" - bl_region_type = "WINDOW" - bl_context = "object" - - def draw(self, context): - self.layout.label("Preprocessing") - row = self.layout.row(align=True) - row.alignment = 'EXPAND' - row.operator("mocap.samples", text='Samples to Beziers') - row.operator("mocap.denoise", text='Clean noise') - row.operator("mocap.rotate_fix", text='Fix BVH Axis Orientation') - row.operator("mocap.scale_fix", text='Auto scale Performer') - row2 = self.layout.row(align=True) - row2.operator("mocap.looper", text='Loop animation') - row2.operator("mocap.limitdof", text='Constrain Rig') - row2.operator("mocap.removelimitdof", text='Unconstrain Rig') - self.layout.label("Retargeting") - enduser_obj = bpy.context.active_object - performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj] - if enduser_obj is None or len(performer_obj) != 1: - self.layout.label("Select performer rig and target rig (as active)") - else: - self.layout.operator("mocap.guessmapping", text="Guess Hiearchy Mapping") - row3 = self.layout.row(align=True) - column1 = row3.column(align=True) - column1.label("Performer Rig") - column2 = row3.column(align=True) - column2.label("Enduser Rig") - performer_obj = performer_obj[0] - if performer_obj.data and enduser_obj.data: - if performer_obj.data.name in bpy.data.armatures and enduser_obj.data.name in bpy.data.armatures: - perf = performer_obj.data - enduser_arm = enduser_obj.data - perf_pose_bones = enduser_obj.pose.bones - for bone in perf.bones: - row = self.layout.row() - row.prop(data=bone, property='foot', text='', icon='POSE_DATA') - row.label(bone.name) - row.prop_search(bone, "map", enduser_arm, "bones") - row.operator("mocap.selectmap", text='', icon='CURSOR').perf_bone = bone.name - label_mod = "FK" - if bone.map: - pose_bone = perf_pose_bones[bone.map] - if pose_bone.is_in_ik_chain: - label_mod = "ik chain" - if hasIKConstraint(pose_bone): - label_mod = "ik end" - row.prop(data=bone, property='twistFix', text='', icon='RNA') - row.prop(pose_bone, 'IKRetarget') - row.label(label_mod) - else: - row.label(" ") - row.label(" ") - mapRow = self.layout.row() - mapRow.operator("mocap.savemapping", text='Save mapping') - mapRow.operator("mocap.loadmapping", text='Load mapping') - self.layout.prop(data=performer_obj.animation_data.action, property='name', text='Action Name') - self.layout.prop(enduser_arm, "advancedRetarget", text='Advanced Retarget') - self.layout.prop(enduser_arm, "frameStep") - self.layout.operator("mocap.retarget", text='RETARGET!') - - -class MocapConstraintsPanel(bpy.types.Panel): - #Motion capture constraints panel - bl_label = "Mocap Fixes" - bl_space_type = "PROPERTIES" - bl_region_type = "WINDOW" - bl_context = "object" - - def draw(self, context): - layout = self.layout - if context.active_object: - if context.active_object.data: - if context.active_object.data.name in bpy.data.armatures: - enduser_obj = context.active_object - enduser_arm = enduser_obj.data - layout.operator_menu_enum("mocap.addmocapfix", "type") - layout.operator("mocap.updateconstraints", text='Update Fixes') - bakeRow = layout.row() - bakeRow.operator("mocap.bakeconstraints", text='Bake Fixes') - bakeRow.operator("mocap.unbakeconstraints", text='Unbake Fixes') - layout.separator() - for i, m_constraint in enumerate(enduser_arm.mocap_constraints): - box = layout.box() - headerRow = box.row() - headerRow.prop(m_constraint, 'show_expanded', text='', icon='TRIA_DOWN' if m_constraint.show_expanded else 'TRIA_RIGHT', emboss=False) - headerRow.prop(m_constraint, 'type', text='') - headerRow.prop(m_constraint, 'name', text='') - headerRow.prop(m_constraint, 'active', icon='MUTE_IPO_ON' if not m_constraint.active else'MUTE_IPO_OFF', text='', emboss=False) - headerRow.operator("mocap.removeconstraint", text="", icon='X', emboss=False).constraint = i - if m_constraint.show_expanded: - box.separator() - box.prop_search(m_constraint, 'constrained_bone', enduser_obj.pose, "bones", icon='BONE_DATA') - if m_constraint.type == "distance" or m_constraint.type == "point": - box.prop_search(m_constraint, 'constrained_boneB', enduser_obj.pose, "bones", icon='CONSTRAINT_BONE') - frameRow = box.row() - frameRow.label("Frame Range:") - frameRow.prop(m_constraint, 's_frame') - frameRow.prop(m_constraint, 'e_frame') - smoothRow = box.row() - smoothRow.label("Smoothing:") - smoothRow.prop(m_constraint, 'smooth_in') - smoothRow.prop(m_constraint, 'smooth_out') - targetRow = box.row() - targetLabelCol = targetRow.column() - targetLabelCol.label("Target settings:") - targetPropCol = targetRow.column() - if m_constraint.type == "floor": - targetPropCol.prop_search(m_constraint, 'targetMesh', bpy.data, "objects") - if m_constraint.type == "point" or m_constraint.type == "freeze": - box.prop(m_constraint, 'targetSpace') - if m_constraint.type == "point": - targetPropCol.prop(m_constraint, 'targetPoint') - if m_constraint.type == "distance" or m_constraint.type == "floor": - targetPropCol.prop(m_constraint, 'targetDist') - layout.separator() - - -class ExtraToolsPanel(bpy.types.Panel): - # Motion capture retargeting panel - bl_label = "Extra Mocap Tools" - bl_space_type = "PROPERTIES" - bl_region_type = "WINDOW" - bl_context = "object" - - def draw(self, context): - layout = self.layout - layout.operator('mocap.pathediting', text="Follow Path") - layout.label("Animation Stitching") - activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) - if activeIsArmature: - enduser_arm = context.active_object.data - layout.label("Retargeted Animations:") - layout.prop_search(enduser_arm, "active_mocap", enduser_arm, "mocapNLATracks") - settings = enduser_arm.stitch_settings - layout.prop_search(settings, "first_action", enduser_arm, "mocapNLATracks") - layout.prop_search(settings, "second_action", enduser_arm, "mocapNLATracks") - layout.prop(settings, "blend_frame") - layout.prop(settings, "blend_amount") - layout.prop(settings, "second_offset") - layout.prop_search(settings, "stick_bone", context.active_object.pose, "bones") - layout.operator('mocap.animstitchguess', text="Guess Settings") - layout.operator('mocap.animstitch', text="Stitch Animations") - - -class OBJECT_OT_RetargetButton(bpy.types.Operator): - #Retargeting operator. Assumes selected and active armatures, where the performer (the selected one) - # has an action for retargeting - '''Retarget animation from selected armature to active armature ''' - bl_idname = "mocap.retarget" - bl_label = "Retargets active action from Performer to Enduser" - bl_options = {'REGISTER', 'UNDO'} - - def execute(self, context): - scene = context.scene - s_frame = scene.frame_start - e_frame = scene.frame_end - enduser_obj = context.active_object - performer_obj = [obj for obj in context.selected_objects if obj != enduser_obj] - if enduser_obj is None or len(performer_obj) != 1: - print("Need active and selected armatures") - else: - performer_obj = performer_obj[0] - s_frame, e_frame = performer_obj.animation_data.action.frame_range - s_frame = int(s_frame) - e_frame = int(e_frame) - if retarget.isRigAdvanced(enduser_obj) and not enduser_obj.data.advancedRetarget: - print("Recommended to use Advanced Retargeting method") - enduser_obj.data.advancedRetarget = True - else: - retarget.totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame) - return {"FINISHED"} - - @classmethod - def poll(cls, context): - if context.active_object: - activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) - performer_obj = [obj for obj in context.selected_objects if obj != context.active_object] - if performer_obj: - return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) and performer_obj[0].animation_data - else: - return False - - -class OBJECT_OT_SaveMappingButton(bpy.types.Operator): - #Operator for saving mapping to enduser armature - '''Save mapping to active armature (for future retargets) ''' - bl_idname = "mocap.savemapping" - bl_label = "Saves user generated mapping from Performer to Enduser" - - def execute(self, context): - enduser_obj = bpy.context.active_object - performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj][0] - retarget.createDictionary(performer_obj.data, enduser_obj.data) - return {"FINISHED"} - - @classmethod - def poll(cls, context): - if context.active_object: - activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) - performer_obj = [obj for obj in context.selected_objects if obj != context.active_object] - if performer_obj: - return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) - else: - return False - - -class OBJECT_OT_LoadMappingButton(bpy.types.Operator): - '''Load saved mapping from active armature''' - #Operator for loading mapping to enduser armature - bl_idname = "mocap.loadmapping" - bl_label = "Loads user generated mapping from Performer to Enduser" - - def execute(self, context): - enduser_obj = bpy.context.active_object - performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj][0] - retarget.loadMapping(performer_obj.data, enduser_obj.data) - return {"FINISHED"} - - @classmethod - def poll(cls, context): - if context.active_object: - activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) - performer_obj = [obj for obj in context.selected_objects if obj != context.active_object] - if performer_obj: - return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) - else: - return False - - -class OBJECT_OT_SelectMapBoneButton(bpy.types.Operator): - #Operator for setting selected bone in enduser armature to the performer mapping - '''Select a bone for faster mapping''' - bl_idname = "mocap.selectmap" - bl_label = "Select a bone for faster mapping" - perf_bone = bpy.props.StringProperty() - - def execute(self, context): - enduser_obj = bpy.context.active_object - performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj][0] - selectedBone = "" - for bone in enduser_obj.data.bones: - boneVis = bone.layers - for i in range(32): - if boneVis[i] and enduser_obj.data.layers[i]: - if bone.select: - selectedBone = bone.name - break - performer_obj.data.bones[self.perf_bone].map = selectedBone - return {"FINISHED"} - - @classmethod - def poll(cls, context): - if context.active_object: - activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) - performer_obj = [obj for obj in context.selected_objects if obj != context.active_object] - if performer_obj: - return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) - else: - return False - - -class OBJECT_OT_ConvertSamplesButton(bpy.types.Operator): - #Operator to convert samples to beziers on the selected object - '''Convert active armature's sampled keyframed to beziers''' - bl_idname = "mocap.samples" - bl_label = "Converts samples / simplifies keyframes to beziers" - - def execute(self, context): - mocap_tools.fcurves_simplify(context, context.active_object) - return {"FINISHED"} - - @classmethod - def poll(cls, context): - return context.active_object.animation_data - - -class OBJECT_OT_LooperButton(bpy.types.Operator): - #Operator to trim fcurves which contain a few loops to a single one on the selected object - '''Trim active armature's animation to a single cycle, given a cyclic animation (such as a walk cycle)''' - bl_idname = "mocap.looper" - bl_label = "loops animation / sampled mocap data" - - def execute(self, context): - mocap_tools.autoloop_anim() - return {"FINISHED"} - - @classmethod - def poll(cls, context): - return context.active_object.animation_data - - -class OBJECT_OT_DenoiseButton(bpy.types.Operator): - #Operator to denoise impluse noise on the active object's fcurves - '''Denoise active armature's animation. Good for dealing with 'bad' frames inherent in mocap animation''' - bl_idname = "mocap.denoise" - bl_label = "Denoises sampled mocap data " - - def execute(self, context): - mocap_tools.denoise_median() - return {"FINISHED"} - - @classmethod - def poll(cls, context): - return context.active_object - - @classmethod - def poll(cls, context): - return context.active_object.animation_data - - -class OBJECT_OT_LimitDOFButton(bpy.types.Operator): - #Operator to analyze performer armature and apply rotation constraints on the enduser armature - '''Create limit constraints on the active armature from the selected armature's animation's range of motion''' - bl_idname = "mocap.limitdof" - bl_label = "Analyzes animations Max/Min DOF and adds hard/soft constraints" - - def execute(self, context): - performer_obj = [obj for obj in context.selected_objects if obj != context.active_object][0] - mocap_tools.limit_dof(context, performer_obj, context.active_object) - return {"FINISHED"} - - @classmethod - def poll(cls, context): - if context.active_object: - activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) - performer_obj = [obj for obj in context.selected_objects if obj != context.active_object] - if performer_obj: - return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) - else: - return False - - -class OBJECT_OT_RemoveLimitDOFButton(bpy.types.Operator): - #Removes constraints created by above operator - '''Removes previously created limit constraints on the active armature''' - bl_idname = "mocap.removelimitdof" - bl_label = "Removes previously created limit constraints on the active armature" - - def execute(self, context): - mocap_tools.limit_dof_toggle_off(context, context.active_object) - return {"FINISHED"} - - @classmethod - def poll(cls, context): - activeIsArmature = False - if context.active_object: - activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) - return activeIsArmature - - -class OBJECT_OT_RotateFixArmature(bpy.types.Operator): - #Operator to fix common imported Mocap data issue of wrong axis system on active object - '''Realign the active armature's axis system to match Blender (Commonly needed after bvh import)''' - bl_idname = "mocap.rotate_fix" - bl_label = "Rotates selected armature 90 degrees (fix for bvh import)" - - def execute(self, context): - mocap_tools.rotate_fix_armature(context.active_object.data) - return {"FINISHED"} - - @classmethod - def poll(cls, context): - if context.active_object: - return isinstance(context.active_object.data, bpy.types.Armature) - - -class OBJECT_OT_ScaleFixArmature(bpy.types.Operator): - #Operator to scale down the selected armature to match the active one - '''Rescale selected armature to match the active animation, for convienence''' - bl_idname = "mocap.scale_fix" - bl_label = "Scales performer armature to match target armature" - - def execute(self, context): - enduser_obj = bpy.context.active_object - performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj][0] - mocap_tools.scale_fix_armature(performer_obj, enduser_obj) - return {"FINISHED"} - - @classmethod - def poll(cls, context): - if context.active_object: - activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) - performer_obj = [obj for obj in context.selected_objects if obj != context.active_object] - if performer_obj: - return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) - else: - return False - - -class MOCAP_OT_AddMocapFix(bpy.types.Operator): - #Operator to add a post-retarget fix - '''Add a post-retarget fix - useful for fixing certain artifacts following the retarget''' - bl_idname = "mocap.addmocapfix" - bl_label = "Add Mocap Fix to target armature" - type = bpy.props.EnumProperty(name="Type of Fix", - items=[("point", "Maintain Position", "Bone is at a specific point"), - ("freeze", "Maintain Position at frame", "Bone does not move from location specified in target frame"), - ("floor", "Stay above", "Bone does not cross specified mesh object eg floor"), - ("distance", "Maintain distance", "Target bones maintained specified distance")], - description="Type of fix") - - def execute(self, context): - enduser_obj = bpy.context.active_object - enduser_arm = enduser_obj.data - new_mcon = enduser_arm.mocap_constraints.add() - new_mcon.type = self.type - return {"FINISHED"} - - @classmethod - def poll(cls, context): - if context.active_object: - return isinstance(context.active_object.data, bpy.types.Armature) - - -class OBJECT_OT_RemoveMocapConstraint(bpy.types.Operator): - #Operator to remove a post-retarget fix - '''Remove this post-retarget fix''' - bl_idname = "mocap.removeconstraint" - bl_label = "Removes fixes from target armature" - constraint = bpy.props.IntProperty() - - def execute(self, context): - enduser_obj = bpy.context.active_object - enduser_arm = enduser_obj.data - m_constraints = enduser_arm.mocap_constraints - m_constraint = m_constraints[self.constraint] - if m_constraint.real_constraint: - bone = enduser_obj.pose.bones[m_constraint.real_constraint_bone] - cons_obj = getConsObj(bone) - removeConstraint(m_constraint, cons_obj) - m_constraints.remove(self.constraint) - return {"FINISHED"} - - @classmethod - def poll(cls, context): - if context.active_object: - return isinstance(context.active_object.data, bpy.types.Armature) - - -class OBJECT_OT_BakeMocapConstraints(bpy.types.Operator): - #Operator to bake all post-retarget fixes - '''Bake all post-retarget fixes to the Retarget Fixes NLA Track''' - bl_idname = "mocap.bakeconstraints" - bl_label = "Bake all fixes to target armature" - - def execute(self, context): - bakeConstraints(context) - return {"FINISHED"} - - @classmethod - def poll(cls, context): - if context.active_object: - return isinstance(context.active_object.data, bpy.types.Armature) - - -class OBJECT_OT_UnbakeMocapConstraints(bpy.types.Operator): - #Operator to unbake all post-retarget fixes - '''Unbake all post-retarget fixes - removes the baked data from the Retarget Fixes NLA Track''' - bl_idname = "mocap.unbakeconstraints" - bl_label = "Unbake all fixes to target armature" - - def execute(self, context): - unbakeConstraints(context) - return {"FINISHED"} - - @classmethod - def poll(cls, context): - if context.active_object: - return isinstance(context.active_object.data, bpy.types.Armature) - - -class OBJECT_OT_UpdateMocapConstraints(bpy.types.Operator): - #Operator to update all post-retarget fixes, similar to update dependencies on drivers - #Needed because python properties lack certain callbacks and some fixes take a while to recalculate. - '''Updates all post-retarget fixes - needed after changes to armature object or pose''' - bl_idname = "mocap.updateconstraints" - bl_label = "Updates all fixes to target armature - neccesary to take under consideration changes to armature object or pose" - - def execute(self, context): - updateConstraints(context.active_object, context) - return {"FINISHED"} - - @classmethod - def poll(cls, context): - if context.active_object: - return isinstance(context.active_object.data, bpy.types.Armature) - - -class OBJECT_OT_GuessHierachyMapping(bpy.types.Operator): - #Operator which calls heurisitic function to guess mapping between 2 armatures - '''Attemps to auto figure out hierarchy mapping''' - bl_idname = "mocap.guessmapping" - bl_label = "Attemps to auto figure out hierarchy mapping" - - def execute(self, context): - enduser_obj = bpy.context.active_object - performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj][0] - mocap_tools.guessMapping(performer_obj, enduser_obj) - return {"FINISHED"} - - @classmethod - def poll(cls, context): - if context.active_object: - activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) - performer_obj = [obj for obj in context.selected_objects if obj != context.active_object] - if performer_obj: - return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature) - else: - return False - - -class OBJECT_OT_PathEditing(bpy.types.Operator): - #Operator which calls path editing function, making active object follow the selected curve. - '''Sets active object (stride object) to follow the selected curve''' - bl_idname = "mocap.pathediting" - bl_label = "Sets active object (stride object) to follow the selected curve" - - def execute(self, context): - path = [obj for obj in context.selected_objects if obj != context.active_object][0] - mocap_tools.path_editing(context, context.active_object, path) - return {"FINISHED"} - - @classmethod - def poll(cls, context): - if context.active_object: - selected_objs = [obj for obj in context.selected_objects if obj != context.active_object and isinstance(obj.data, bpy.types.Curve)] - return selected_objs - else: - return False - - -class OBJECT_OT_AnimationStitchingButton(bpy.types.Operator): - #Operator which calls stitching function, combining 2 animations onto the NLA. - '''Stitches two defined animations into a single one via alignment of NLA Tracks''' - bl_idname = "mocap.animstitch" - bl_label = "Stitches two defined animations into a single one via alignment of NLA Tracks" - - def execute(self, context): - mocap_tools.anim_stitch(context, context.active_object) - return {"FINISHED"} - - @classmethod - def poll(cls, context): - activeIsArmature = False - if context.active_object: - activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) - if activeIsArmature: - stitch_settings = context.active_object.data.stitch_settings - return (stitch_settings.first_action and stitch_settings.second_action) - return False - - -class OBJECT_OT_GuessAnimationStitchingButton(bpy.types.Operator): - #Operator which calls stitching function heuristic, setting good values for above operator. - '''Guesses the stitch frame and second offset for animation stitch''' - bl_idname = "mocap.animstitchguess" - bl_label = "Guesses the stitch frame and second offset for animation stitch" - - def execute(self, context): - mocap_tools.guess_anim_stitch(context, context.active_object) - return {"FINISHED"} - - @classmethod - def poll(cls, context): - activeIsArmature = False - if context.active_object: - activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) - if activeIsArmature: - stitch_settings = context.active_object.data.stitch_settings - return (stitch_settings.first_action and stitch_settings.second_action) - return False - - -def register(): - bpy.utils.register_module(__name__) - - -def unregister(): - bpy.utils.unregister_module(__name__) - -if __name__ == "__main__": - register() -- cgit v1.2.3 From c07bd1439a3f026b8603c52662c3e7ccc364321a Mon Sep 17 00:00:00 2001 From: Peter Schlaile Date: Sun, 28 Aug 2011 14:46:03 +0000 Subject: == Sequencer == This patch adds: * support for proxy building again (missing feature from Blender 2.49) additionally to the way, Blender 2.49 worked, you can select several strips at once and make Blender build proxies in the background (using the job system) Also a new thing: movie proxies are now build into AVI files, and the proxy system is moved into ImBuf-library, so that other parts of blender can also benefit from it. * Timecode support: to fix seeking issues with files, that have a) varying frame rates b) very large GOP lengths c) are broken inbetween d) use different time code tracks the proxy builder can now also build timecode indices, which are used (optionally) for seeking. For the first time, it is possible, to do frame exact seeking on all file types. * Support for different video-streams in one video file (can be selected in sequencer, other parts of blender can also use it, but UI has to be added accordingly) * IMPORTANT: this patch *requires* ffmpeg 0.7 or newer, since older versions don't support the pkt_pts field, that is essential for building timecode indices. Windows and Mac libs are already updated, Linux-users have to build their own ffmpeg verions until distros keep up. --- release/scripts/startup/bl_ui/space_sequencer.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 84cc365425e..1902e9345d6 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -60,6 +60,7 @@ class SEQUENCER_HT_header(Header): layout.separator() layout.operator("sequencer.refresh_all") + layout.template_running_jobs() elif st.view_type == 'SEQUENCER_PREVIEW': layout.separator() layout.operator("sequencer.refresh_all") @@ -241,6 +242,7 @@ class SEQUENCER_MT_strip(Menu): layout.operator("sequencer.images_separate") layout.operator("sequencer.offset_clear") layout.operator("sequencer.deinterlace_selected_movies") + layout.operator("sequencer.rebuild_proxy") layout.separator() layout.operator("sequencer.duplicate") @@ -578,6 +580,7 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel): col = split.column() col.prop(strip, "filepath", text="") col.prop(strip, "mpeg_preseek", text="MPEG Preseek") + col.prop(strip, "streamindex", text="Stream Index") # TODO, sound??? # end drawing filename @@ -746,7 +749,7 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel): class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel): - bl_label = "Proxy" + bl_label = "Proxy / Timecode" @classmethod def poll(cls, context): @@ -772,12 +775,29 @@ class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel): flow = layout.column_flow() flow.prop(strip, "use_proxy_custom_directory") flow.prop(strip, "use_proxy_custom_file") - if strip.proxy: # TODO - need to add this somehow + if strip.proxy: if strip.use_proxy_custom_directory and not strip.use_proxy_custom_file: flow.prop(strip.proxy, "directory") if strip.use_proxy_custom_file: flow.prop(strip.proxy, "filepath") + row = layout.row() + row.prop(strip.proxy, "build_25") + row.prop(strip.proxy, "build_50") + row.prop(strip.proxy, "build_75") + row.prop(strip.proxy, "build_100") + + col = layout.column() + col.label(text="Build JPEG quality") + col.prop(strip.proxy, "quality") + + if strip.type == "MOVIE": + col = layout.column() + col.label(text="Use timecode index:") + + col.prop(strip.proxy, "timecode") + + class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, Panel): bl_label = "Scene Preview/Render" -- cgit v1.2.3 From 5bac37f6d4d2e8d584ae0ec6bafd2808c47fbb25 Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Mon, 29 Aug 2011 15:01:55 +0000 Subject: * Reverting Titlecard commit r37537 * Reverting update recent files commit r37155 * Turning reference counts into unsigned ints * Minor things --- release/scripts/startup/bl_ui/space_sequencer.py | 14 +++----------- release/scripts/startup/bl_ui/space_userpref.py | 1 - 2 files changed, 3 insertions(+), 12 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index cebe78ff627..168a025c407 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -225,7 +225,6 @@ class SEQUENCER_MT_add_effect(Menu): layout.operator("sequencer.effect_strip_add", text="Speed Control").type = 'SPEED' layout.operator("sequencer.effect_strip_add", text="Multicam Selector").type = 'MULTICAM' layout.operator("sequencer.effect_strip_add", text="Adjustment Layer").type = 'ADJUSTMENT' - layout.operator("sequencer.effect_strip_add", text="Title Card").type = 'TITLE_CARD' class SEQUENCER_MT_strip(Menu): @@ -407,7 +406,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): 'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP', 'PLUGIN', 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', 'SPEED', - 'MULTICAM', 'ADJUSTMENT', 'TITLE_CARD'} + 'MULTICAM', 'ADJUSTMENT'} def draw(self, context): layout = self.layout @@ -475,11 +474,6 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): row.label("Cut To") for i in range(1, strip.channel): row.operator("sequencer.cut_multicam", text=str(i)).camera = i - elif strip.type == "TITLE_CARD": - layout.prop(strip, "title") - layout.prop(strip, "subtitle") - layout.prop(strip, "color_foreground") - layout.prop(strip, "color_background") col = layout.column(align=True) if strip.type == 'SPEED': @@ -551,8 +545,7 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel): 'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP', 'PLUGIN', 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', - 'MULTICAM', 'SPEED', 'ADJUSTMENT', - 'TITLE_CARD'} + 'MULTICAM', 'SPEED', 'ADJUSTMENT'} def draw(self, context): layout = self.layout @@ -713,8 +706,7 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel): 'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP', 'PLUGIN', 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', - 'MULTICAM', 'SPEED', 'ADJUSTMENT', - 'TITLE_CARD'} + 'MULTICAM', 'SPEED', 'ADJUSTMENT'} def draw(self, context): layout = self.layout diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 79565030e56..13edc3471d2 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -746,7 +746,6 @@ class USERPREF_PT_file(Panel): col.prop(paths, "save_version") col.prop(paths, "recent_files") - col.prop(paths, "use_update_recent_files_on_load") col.prop(paths, "use_save_preview_images") col.label(text="Auto Save:") col.prop(paths, "use_auto_save_temporary_files") -- cgit v1.2.3 From d049a722fea3d150fbfad06ffdbbb5c150717134 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 30 Aug 2011 04:13:48 +0000 Subject: fix [#28413] bpy.ops.nla.bake can't bake from frame 0 --- release/scripts/startup/bl_operators/nla.py | 33 ++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_operators/nla.py b/release/scripts/startup/bl_operators/nla.py index 714b889da26..cf595b1adf4 100644 --- a/release/scripts/startup/bl_operators/nla.py +++ b/release/scripts/startup/bl_operators/nla.py @@ -200,19 +200,32 @@ class BakeAction(Operator): bl_label = "Bake Action" bl_options = {'REGISTER', 'UNDO'} - frame_start = IntProperty(name="Start Frame", + frame_start = IntProperty( + name="Start Frame", description="Start frame for baking", - default=1, min=1, max=300000) - frame_end = IntProperty(name="End Frame", + min=0, max=300000, + default=1, + ) + frame_end = IntProperty( + name="End Frame", description="End frame for baking", - default=250, min=1, max=300000) - step = IntProperty(name="Frame Step", + min=1, max=300000, + default=250, + ) + step = IntProperty( + name="Frame Step", description="Frame Step", - default=1, min=1, max=120) - only_selected = BoolProperty(name="Only Selected", - default=True) - clear_consraints = BoolProperty(name="Clear Constraints", - default=False) + min=1, max=120, + default=1, + ) + only_selected = BoolProperty( + name="Only Selected", + default=True, + ) + clear_consraints = BoolProperty( + name="Clear Constraints", + default=False, + ) bake_types = EnumProperty( name="Bake Data", options={'ENUM_FLAG'}, -- cgit v1.2.3 From 6c9ee34dd8acba35808847d3669798c6d3459b9c Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Tue, 30 Aug 2011 10:44:02 +0000 Subject: 2.5 UI Files: * Code cleanup after Pepper merge. --- release/scripts/startup/bl_ui/properties_data_armature.py | 3 +-- release/scripts/startup/bl_ui/properties_data_speaker.py | 8 ++------ release/scripts/startup/bl_ui/properties_object_constraint.py | 5 +---- release/scripts/startup/bl_ui/properties_render.py | 9 +++------ release/scripts/startup/bl_ui/properties_scene.py | 2 -- 5 files changed, 7 insertions(+), 20 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py index 9a76ed81530..b2c09469067 100644 --- a/release/scripts/startup/bl_ui/properties_data_armature.py +++ b/release/scripts/startup/bl_ui/properties_data_armature.py @@ -72,8 +72,7 @@ class DATA_PT_skeleton(ArmatureButtonsPanel, Panel): flow.prop(arm, "use_deform_preserve_volume", text="Quaternion") if context.scene.render.engine == "BLENDER_GAME": - col = layout.column() - col.prop(arm, "vert_deformer") + layout.row().prop(arm, "vert_deformer", expand=True, text="") class DATA_PT_display(ArmatureButtonsPanel, Panel): bl_label = "Display" diff --git a/release/scripts/startup/bl_ui/properties_data_speaker.py b/release/scripts/startup/bl_ui/properties_data_speaker.py index fe9f798af0c..657c0fe652a 100644 --- a/release/scripts/startup/bl_ui/properties_data_speaker.py +++ b/release/scripts/startup/bl_ui/properties_data_speaker.py @@ -66,10 +66,7 @@ class DATA_PT_speaker(DataButtonsPanel, bpy.types.Panel): split.template_ID(speaker, "sound", open="sound.open_mono") split.prop(speaker, "muted") - split = layout.split() - - row = split.row() - + row = layout.row() row.prop(speaker, "volume") row.prop(speaker, "pitch") @@ -84,15 +81,14 @@ class DATA_PT_distance(DataButtonsPanel, bpy.types.Panel): speaker = context.speaker split = layout.split() + col = split.column() - col.label("Volume:") col.prop(speaker, "volume_min", text="Minimum") col.prop(speaker, "volume_max", text="Maximum") col.prop(speaker, "attenuation") col = split.column() - col.label("Distance:") col.prop(speaker, "distance_max", text="Maximum") col.prop(speaker, "distance_reference", text="Reference") diff --git a/release/scripts/startup/bl_ui/properties_object_constraint.py b/release/scripts/startup/bl_ui/properties_object_constraint.py index c74a0000499..ba237e74fb7 100644 --- a/release/scripts/startup/bl_ui/properties_object_constraint.py +++ b/release/scripts/startup/bl_ui/properties_object_constraint.py @@ -235,7 +235,6 @@ class ConstraintButtonsPanel(): row.label() def LIMIT_ROTATION(self, context, layout, con): - split = layout.split() col = split.column(align=True) @@ -259,9 +258,7 @@ class ConstraintButtonsPanel(): sub.prop(con, "min_z", text="Min") sub.prop(con, "max_z", text="Max") - row = layout.row() - row.prop(con, "use_transform_limit") - row.label() + layout.prop(con, "use_transform_limit") row = layout.row() row.label(text="Convert:") diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index c906013e094..395cfc6934e 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -592,12 +592,9 @@ class RENDER_PT_encoding(RenderButtonsPanel, Panel): if rd.ffmpeg_format not in {'MP3'}: layout.prop(rd, "ffmpeg_audio_codec", text="Audio Codec") - split = layout.split() - - col = split.column() - col.prop(rd, "ffmpeg_audio_bitrate") - col = split.column() - col.prop(rd, "ffmpeg_audio_volume", slider=True) + row = layout.row() + row.prop(rd, "ffmpeg_audio_bitrate") + row.prop(rd, "ffmpeg_audio_volume", slider=True) class RENDER_PT_bake(RenderButtonsPanel, Panel): diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py index fd7fc8ed462..66f967bb6e1 100644 --- a/release/scripts/startup/bl_ui/properties_scene.py +++ b/release/scripts/startup/bl_ui/properties_scene.py @@ -59,14 +59,12 @@ class SCENE_PT_audio(SceneButtonsPanel, Panel): split = layout.split() col = split.column() - col.label("Listener:") col.prop(scene, "audio_distance_model", text="") col.prop(scene, "audio_doppler_speed", text="Speed") col.prop(scene, "audio_doppler_factor", text="Doppler") col = split.column() - col.label("Format:") col.prop(rd, "ffmpeg_audio_channels", text="") col.prop(rd, "ffmpeg_audio_mixrate", text="Rate") -- cgit v1.2.3 From b20c9b0ba368d5685d3c996572780befe852b889 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 30 Aug 2011 10:49:58 +0000 Subject: minor edits, pep8 - also correct float -> double promotion for blf. --- release/scripts/modules/bpy_types.py | 2 +- release/scripts/startup/bl_operators/nla.py | 4 +-- release/scripts/startup/bl_operators/object.py | 27 ++++++++++-------- .../startup/bl_ui/properties_data_armature.py | 1 + .../startup/bl_ui/properties_object_constraint.py | 1 - .../scripts/startup/bl_ui/properties_texture.py | 8 +++--- release/scripts/startup/bl_ui/space_dopesheet.py | 2 +- release/scripts/startup/bl_ui/space_nla.py | 4 +-- release/scripts/startup/bl_ui/space_sequencer.py | 1 - release/scripts/startup/bl_ui/space_view3d.py | 5 ++-- release/scripts/startup/keyingsets_builtins.py | 33 +++++++++++----------- 11 files changed, 46 insertions(+), 42 deletions(-) (limited to 'release') diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index e4a0d30efcf..101416f4943 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -413,7 +413,7 @@ TypeMap = {} class Sound(bpy_types.ID): __slots__ = () - + @property def factory(self): """The aud.Factory object of the sound.""" diff --git a/release/scripts/startup/bl_operators/nla.py b/release/scripts/startup/bl_operators/nla.py index 085cd75f9f9..c764f7d62f1 100644 --- a/release/scripts/startup/bl_operators/nla.py +++ b/release/scripts/startup/bl_operators/nla.py @@ -269,10 +269,8 @@ class BakeAction(Operator): wm = context.window_manager return wm.invoke_props_dialog(self) -################################# - -class ClearUselessActions(bpy.types.Operator): +class ClearUselessActions(Operator): '''Mark actions with no F-Curves for deletion after save+reload of file preserving "action libraries"''' bl_idname = "anim.clear_useless_actions" bl_label = "Clear Useless Actions" diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py index 88f863b8e55..6c9f27afaa5 100644 --- a/release/scripts/startup/bl_operators/object.py +++ b/release/scripts/startup/bl_operators/object.py @@ -686,26 +686,30 @@ class ClearAllRestrictRender(Operator): obj.hide_render = False return {'FINISHED'} -class TransformsToDeltasAnim(bpy.types.Operator): + +class TransformsToDeltasAnim(Operator): '''Convert object animation for normal transforms to delta transforms''' bl_idname = "object.anim_transforms_to_deltas" bl_label = "Animated Transforms to Deltas" bl_options = {'REGISTER', 'UNDO'} - + @classmethod def poll(cls, context): obs = context.selected_editable_objects return (obs is not None) - + def execute(self, context): for obj in context.selected_editable_objects: # get animation data adt = obj.animation_data if (adt is None) or (adt.action is None): - self.report({'WARNING'}, "No animation data to convert on object: " + obj.name) + self.report({'WARNING'}, + "No animation data to convert on object: %r" % + obj.name) continue - - # if F-Curve uses standard transform path, just append "delta_" to this path + + # if F-Curve uses standard transform path + # just append "delta_" to this path for fcu in adt.action.fcurves: if fcu.data_path == "location": fcu.data_path = "delta_location" @@ -716,13 +720,14 @@ class TransformsToDeltasAnim(bpy.types.Operator): elif fcu.data_path == "rotation_quaternion": fcu.data_path = "delta_rotation_quaternion" obj.rotation_quaternion.identity() - #elif fcu.data_path == "rotation_axis_angle": # XXX: currently not implemented - # fcu.data_path = "delta_rotation_axis_angle" + # XXX: currently not implemented + # elif fcu.data_path == "rotation_axis_angle": + # fcu.data_path = "delta_rotation_axis_angle" elif fcu.data_path == "scale": fcu.data_path = "delta_scale" - obj.scale = (1, 1, 1) - + obj.scale = 1.0, 1.0, 1.0 + # hack: force animsys flush by changing frame, so that deltas get run context.scene.frame_set(context.scene.frame_current) - + return {'FINISHED'} diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py index b2c09469067..3d1903f4cbc 100644 --- a/release/scripts/startup/bl_ui/properties_data_armature.py +++ b/release/scripts/startup/bl_ui/properties_data_armature.py @@ -74,6 +74,7 @@ class DATA_PT_skeleton(ArmatureButtonsPanel, Panel): if context.scene.render.engine == "BLENDER_GAME": layout.row().prop(arm, "vert_deformer", expand=True, text="") + class DATA_PT_display(ArmatureButtonsPanel, Panel): bl_label = "Display" diff --git a/release/scripts/startup/bl_ui/properties_object_constraint.py b/release/scripts/startup/bl_ui/properties_object_constraint.py index ba237e74fb7..05fac2026a0 100644 --- a/release/scripts/startup/bl_ui/properties_object_constraint.py +++ b/release/scripts/startup/bl_ui/properties_object_constraint.py @@ -478,7 +478,6 @@ class ConstraintButtonsPanel(): row.prop(con, "use_transform_limit") row.label() - def STRETCH_TO(self, context, layout, con): self.target_template(layout, con) diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py index 0172fbcbadd..34f5a948ee7 100644 --- a/release/scripts/startup/bl_ui/properties_texture.py +++ b/release/scripts/startup/bl_ui/properties_texture.py @@ -414,7 +414,7 @@ class TEXTURE_PT_image_sampling(TextureTypePanel, Panel): row = col.row() row.active = tex.use_normal_map row.prop(slot, "normal_map_space", text="") - + row = col.row() row.active = not tex.use_normal_map row.prop(tex, "use_derivative_map") @@ -1029,14 +1029,14 @@ class TEXTURE_PT_influence(TextureSlotPanel, Panel): # only show bump settings if activated but not for normalmap images row = layout.row() - + sub = row.row() sub.active = (tex.use_map_normal or tex.use_map_warp) and not (tex.texture.type == 'IMAGE' and (tex.texture.use_normal_map or tex.texture.use_derivative_map)) sub.prop(tex, "bump_method", text="Method") - # the space setting is supported for: derivmaps + bumpmaps (DEFAULT,BEST_QUALITY), not for normalmaps + # the space setting is supported for: derivmaps + bumpmaps (DEFAULT,BEST_QUALITY), not for normalmaps sub = row.row() - sub.active = (tex.use_map_normal or tex.use_map_warp) and not (tex.texture.type == 'IMAGE' and tex.texture.use_normal_map) and ((tex.bump_method in {'BUMP_DEFAULT', 'BUMP_BEST_QUALITY'}) or (tex.texture.type == 'IMAGE' and tex.texture.use_derivative_map)) + sub.active = (tex.use_map_normal or tex.use_map_warp) and not (tex.texture.type == 'IMAGE' and tex.texture.use_normal_map) and ((tex.bump_method in {'BUMP_DEFAULT', 'BUMP_BEST_QUALITY'}) or (tex.texture.type == 'IMAGE' and tex.texture.use_derivative_map)) sub.prop(tex, "bump_objectspace", text="Space") diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 5ed79f45fbc..90dcc99e6d7 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -36,7 +36,7 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False): if is_nla: row.prop(dopesheet, "show_missing_nla", text="") - + if not genericFiltersOnly: if bpy.data.groups: row = layout.row(align=True) diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py index 1d4b7c6828f..ffead81c507 100644 --- a/release/scripts/startup/bl_ui/space_nla.py +++ b/release/scripts/startup/bl_ui/space_nla.py @@ -69,11 +69,11 @@ class NLA_MT_view(Menu): layout.separator() layout.operator("anim.previewrange_set") layout.operator("anim.previewrange_clear") - + layout.separator() layout.operator("nla.view_all") layout.operator("nla.view_selected") - + layout.separator() layout.operator("screen.area_dupli") layout.operator("screen.screen_full_area") diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 8592cc2fcc0..36f606da635 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -804,7 +804,6 @@ class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel): col.prop(strip.proxy, "timecode") - class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, Panel): bl_label = "Scene Preview/Render" bl_space_type = 'SEQUENCE_EDITOR' diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 64cbc4c3d98..9f96df1eb66 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -179,9 +179,9 @@ class VIEW3D_MT_transform(Menu): layout.operator("object.randomize_transform") layout.operator("object.align") - + layout.separator() - + layout.operator("object.anim_transforms_to_deltas") @@ -1273,6 +1273,7 @@ class VIEW3D_MT_pose_transform(Menu): layout.operator("pose.user_transforms_clear", text="Reset unkeyed") + class VIEW3D_MT_pose_slide(Menu): bl_label = "In-Betweens" diff --git a/release/scripts/startup/keyingsets_builtins.py b/release/scripts/startup/keyingsets_builtins.py index dcc1afed74b..6b12c95e072 100644 --- a/release/scripts/startup/keyingsets_builtins.py +++ b/release/scripts/startup/keyingsets_builtins.py @@ -32,13 +32,14 @@ in lost (i.e. unkeyed) animation. import bpy import keyingsets_utils +from bpy.types import KeyingSetInfo ############################### # Built-In KeyingSets # Location -class BUILTIN_KSI_Location(bpy.types.KeyingSetInfo): +class BUILTIN_KSI_Location(KeyingSetInfo): bl_label = "Location" # poll - use predefined callback for selected bones/objects @@ -52,7 +53,7 @@ class BUILTIN_KSI_Location(bpy.types.KeyingSetInfo): # Rotation -class BUILTIN_KSI_Rotation(bpy.types.KeyingSetInfo): +class BUILTIN_KSI_Rotation(KeyingSetInfo): bl_label = "Rotation" # poll - use predefined callback for selected bones/objects @@ -66,7 +67,7 @@ class BUILTIN_KSI_Rotation(bpy.types.KeyingSetInfo): # Scale -class BUILTIN_KSI_Scaling(bpy.types.KeyingSetInfo): +class BUILTIN_KSI_Scaling(KeyingSetInfo): bl_label = "Scaling" # poll - use predefined callback for selected bones/objects @@ -82,7 +83,7 @@ class BUILTIN_KSI_Scaling(bpy.types.KeyingSetInfo): # LocRot -class BUILTIN_KSI_LocRot(bpy.types.KeyingSetInfo): +class BUILTIN_KSI_LocRot(KeyingSetInfo): bl_label = "LocRot" # poll - use predefined callback for selected bones/objects @@ -100,7 +101,7 @@ class BUILTIN_KSI_LocRot(bpy.types.KeyingSetInfo): # LocScale -class BUILTIN_KSI_LocScale(bpy.types.KeyingSetInfo): +class BUILTIN_KSI_LocScale(KeyingSetInfo): bl_label = "LocScale" # poll - use predefined callback for selected bones/objects @@ -118,7 +119,7 @@ class BUILTIN_KSI_LocScale(bpy.types.KeyingSetInfo): # LocRotScale -class BUILTIN_KSI_LocRotScale(bpy.types.KeyingSetInfo): +class BUILTIN_KSI_LocRotScale(KeyingSetInfo): bl_label = "LocRotScale" # poll - use predefined callback for selected bones/objects @@ -138,7 +139,7 @@ class BUILTIN_KSI_LocRotScale(bpy.types.KeyingSetInfo): # RotScale -class BUILTIN_KSI_RotScale(bpy.types.KeyingSetInfo): +class BUILTIN_KSI_RotScale(KeyingSetInfo): bl_label = "RotScale" # poll - use predefined callback for selected bones/objects @@ -158,7 +159,7 @@ class BUILTIN_KSI_RotScale(bpy.types.KeyingSetInfo): # Location -class BUILTIN_KSI_VisualLoc(bpy.types.KeyingSetInfo): +class BUILTIN_KSI_VisualLoc(KeyingSetInfo): bl_label = "Visual Location" bl_options = {'INSERTKEY_VISUAL'} @@ -174,7 +175,7 @@ class BUILTIN_KSI_VisualLoc(bpy.types.KeyingSetInfo): # Rotation -class BUILTIN_KSI_VisualRot(bpy.types.KeyingSetInfo): +class BUILTIN_KSI_VisualRot(KeyingSetInfo): bl_label = "Visual Rotation" bl_options = {'INSERTKEY_VISUAL'} @@ -190,7 +191,7 @@ class BUILTIN_KSI_VisualRot(bpy.types.KeyingSetInfo): # VisualLocRot -class BUILTIN_KSI_VisualLocRot(bpy.types.KeyingSetInfo): +class BUILTIN_KSI_VisualLocRot(KeyingSetInfo): bl_label = "Visual LocRot" bl_options = {'INSERTKEY_VISUAL'} @@ -212,7 +213,7 @@ class BUILTIN_KSI_VisualLocRot(bpy.types.KeyingSetInfo): # Available -class BUILTIN_KSI_Available(bpy.types.KeyingSetInfo): +class BUILTIN_KSI_Available(KeyingSetInfo): bl_label = "Available" # poll - selected objects or selected object with animation data @@ -234,7 +235,7 @@ class BUILTIN_KSI_Available(bpy.types.KeyingSetInfo): # All properties that are likely to get animated in a character rig -class BUILTIN_KSI_WholeCharacter(bpy.types.KeyingSetInfo): +class BUILTIN_KSI_WholeCharacter(KeyingSetInfo): bl_label = "Whole Character" # these prefixes should be avoided, as they are not really bones @@ -265,7 +266,7 @@ class BUILTIN_KSI_WholeCharacter(bpy.types.KeyingSetInfo): # loc, rot, scale - only include unlocked ones ksi.doLoc(ks, bone) - if bone.rotation_mode in ('QUATERNION', 'AXIS_ANGLE'): + if bone.rotation_mode in {'QUATERNION', 'AXIS_ANGLE'}: ksi.doRot4d(ks, bone) else: ksi.doRot3d(ks, bone) @@ -365,7 +366,7 @@ class BUILTIN_KSI_WholeCharacter(bpy.types.KeyingSetInfo): # Delta Location -class BUILTIN_KSI_DeltaLocation(bpy.types.KeyingSetInfo): +class BUILTIN_KSI_DeltaLocation(KeyingSetInfo): bl_label = "Delta Location" # poll - selected objects only (and only if active object in object mode) @@ -390,7 +391,7 @@ class BUILTIN_KSI_DeltaLocation(bpy.types.KeyingSetInfo): # Delta Rotation -class BUILTIN_KSI_DeltaRotation(bpy.types.KeyingSetInfo): +class BUILTIN_KSI_DeltaRotation(KeyingSetInfo): bl_label = "Delta Rotation" # poll - selected objects only (and only if active object in object mode) @@ -423,7 +424,7 @@ class BUILTIN_KSI_DeltaRotation(bpy.types.KeyingSetInfo): # Delta Scale -class BUILTIN_KSI_DeltaScale(bpy.types.KeyingSetInfo): +class BUILTIN_KSI_DeltaScale(KeyingSetInfo): bl_label = "Delta Scale" # poll - selected objects only (and only if active object in object mode) -- cgit v1.2.3 From 047e8224b14aa7836db3b067824258e49e8602db Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Tue, 30 Aug 2011 11:31:48 +0000 Subject: Fix for my last commit. --- release/scripts/startup/bl_ui/properties_data_armature.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py index 3d1903f4cbc..e17064178b8 100644 --- a/release/scripts/startup/bl_ui/properties_data_armature.py +++ b/release/scripts/startup/bl_ui/properties_data_armature.py @@ -72,8 +72,7 @@ class DATA_PT_skeleton(ArmatureButtonsPanel, Panel): flow.prop(arm, "use_deform_preserve_volume", text="Quaternion") if context.scene.render.engine == "BLENDER_GAME": - layout.row().prop(arm, "vert_deformer", expand=True, text="") - + layout.row().prop(arm, "vert_deformer", expand=True) class DATA_PT_display(ArmatureButtonsPanel, Panel): bl_label = "Display" -- cgit v1.2.3 From 0de9af375b5a437ab50d1d1725195ddaa35607c9 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Tue, 30 Aug 2011 12:45:56 +0000 Subject: 2.5 Game UI: *Fix for clutter after pepper merge, 3 booleans in one row, is 1 too much here ;-) --- release/scripts/startup/bl_ui/properties_game.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'release') diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py index e3c576e7093..161e4b10cff 100644 --- a/release/scripts/startup/bl_ui/properties_game.py +++ b/release/scripts/startup/bl_ui/properties_game.py @@ -340,10 +340,12 @@ class RENDER_PT_game_performance(RenderButtonsPanel, Panel): layout = self.layout gs = context.scene.game_settings - row = layout.row() + col = layout.column() + row = col.row() row.prop(gs, "use_frame_rate") row.prop(gs, "use_display_lists") - row.prop(gs, "restrict_animation_updates") + + col.prop(gs, "restrict_animation_updates") class RENDER_PT_game_display(RenderButtonsPanel, Panel): -- cgit v1.2.3