Help with armature object

Hi all,

I’m trying to do some simple armature manipulation with a script.

The first example on this page: http://www.blender.org/documentation/242PythonDoc/Armature-module.html gives me some problems, however. Is this documentation not supposed to be up to date?

Line 13 looks like this and generates this error:


	eb.parent = arm.bones['Bone.003']
	KeyError: 'bone Bone.003 not found'

arm is an armature, eb an editbone. Even though the armature has a bone of that name. I can uncomment some of the lines and get some other errors, however the worst thing is this (command & error):


	arm.update()  #save changes
	AttributeError: ArmatureType - Bad Arguments:
	  The armature must be linked to an object before you can save changes!

What gives? Is the example wrong, or the API broken? Is my Python setup wrong, or am I completely misunderstanding something?

Any info / starting points / example scripts would be greatly appreciated.

I’m running Blender 2.42a, Python 2.4 OSX (PPC)

It should be mentioned that I’ve only done little Blender Python before. I’m not new to programming in general. I’m used to looking at documentation, and figuring stuff out, bug squashing etc.

I’m just wondering why an example script like that isn’t working, while downloadable scripts do. If I cut’n’paste lines from working scripts, I can’t get them to work in my own context, so there’s probably something basic that I’m missing.

Any help to get on track would be great.

Holy crap. Spammer on the port bow.

Oh damn! Don’t know how that happened!

A preview error?

I’m so very, very sorry! I’ll see if I can somehow report this for moderation.

Well, just an update to post my script.

As you can guess, I solved the problems. Some of them, anyways - a lot of this armature / pose stuff is hard to get at. It won’t copy everything, but as close as I could get. And it probably doesn’t follow Blender conventions, but it should be clear enough to be used by other people.

So, here it is:


from Blender import *

##
## bonecopy 0.05 by Simon Bækdahl Nielsen
## Do with this script whatever you like.
## It will duplicate an entire armature, and keep relative
## parents and constraint targets.
## For now, it doesn't copy armature
## layers and custom bone objects, but
## will keep as many settings as I could manage.
## 
## Usage: Select your armature in object mode, 
## open this script in Blender's text editor,
## then enter your settings below, and press alt-P to run it.
##
## Be sure to save a copy of your work first!
## 
## I hope it works for you, but there are no guarantees.
##

## setup 

numberOfCopies = 1

offsetX = 0
offsetY = 0
offsetZ = 3

## Add the names of bones you don't want copied to this list,
## in the form ["bonename1", "bonename2", etc]. Duplicated
## children of bones in this list will also be children of the
## original bone.

dontCopy = []

##  end setup

##
##   functions
##

def copyBone(bone, appendToName):
	
	editBone = Armature.Editbone()

	editBone.tail = bone.tail #Mathutils.Vector(3,4,0)
	editBone.head = bone.head #Mathutils.Vector(0,0,10)	
	
	newBoneName = bone.name + appendToName
	arm.bones[newBoneName] = editBone
	
	return newBoneName

def connectBone(origBone, newBone, appendToName):
	newOptions = origBone.options	
	
	try:
		origParent = origBone.parent.name
		#print "origParent: ", origParent
		
		#need to check for non-copied parents
		if dontCopy.count(origParent) != 0:
			# parent is in dontCopy list, use original
			newParent = origParent
			
			#but make sure it's not connected
			#print "options before: ", newOptions
			modifiedOptions = []
			for option in newOptions:
				#print "option: ", option
				if option != Armature.CONNECTED:
					modifiedOptions.append(option)
			newOptions = modifiedOptions
			#print "options after: ", newOptions

		else:
			# parent has been copied, use copy
			newParent = origParent + appendToName

		print "parenting: ", newBone.name, "to: ", newParent
		newBone.parent = arm.bones[newParent]
	except:
		error = 1

	newBone.options = newOptions	
	newBone.deformDist = origBone.deformDist
	
	newBone.roll = origBone.roll
	
	try:
		newBone.subdivision = origBone.subdivision
	except:
		error=1
		
	newBone.weight = origBone.weight

	
def translateBone(bone):
	bone.tail = bone.tail + translateVector
	bone.head = bone.head + translateVector

def copyConstraint(originalBone, newBone, appendToName):

	try:
		#print "limitmax: ", originalBone.limitmax
		newBone.limitmax = originalBone.limitmax
	except:
		error = 1

	try:
		newBone.limitmin = originalBone.limitmin
	except:
		error = 1

	try:
		for constraint in originalBone.constraints:
			currentConstraint = newBone.constraints.append(constraint.type)
			print 'Copying constraint: ', constraint, " from: ", originalBone.name, " to: ", newBone.name
			#get the constants corresponding to constraint settings
			for constraintKey in Constraint.Settings.values():
				try:
					#copy the settings
					currentConstraint[constraintKey] = constraint[constraintKey]
				except:
					error = 1
			#we need to check for target bone, and change it
			try:
				if constraint[Constraint.Settings.BONE] != "" :
					
					if dontCopy.count(constraint[Constraint.Settings.BONE]) != 0:
						#target is in nocopy list, keep original
						newTargetBoneName = constraint[Constraint.Settings.BONE]
					else:
						newTargetBoneName = constraint[Constraint.Settings.BONE] + appendToName
					
					print "Setting target bone: ", newTargetBoneName
					currentConstraint[Constraint.Settings.BONE] = newTargetBoneName

			except:
				error = 1
	except:
		error = 1
			

##				
##   main    ######
##

print
print "***********************"
print "Beginning bonecopy 0.05"
print

ob = Object.GetSelected()

if len(ob) <> 1:
	print "please select exactly one armature"
else:
	firstOb = ob[0]
	if firstOb.getType() <> "Armature":
		print "Selected object is not an armature."
	else:
		arm = Armature.Get(firstOb.getName())
				
		print "Duplicating bones in armature: ", arm
		print
		
		#make a list of the existing bones
		originalBoneNames = []
		for bone in arm.bones.values():
			if dontCopy.count(bone.name) == 0:
				originalBoneNames.append(bone.name)
			
		#make the armature editable
		arm.makeEditable()

		#copy the bones:
		translateVectorStep = Mathutils.Vector(offsetX,offsetY,offsetZ)
		translateVector = Mathutils.Vector(0,0,0)
		copiedBones = []

		#loop through number of copies		
		for i in range (0,numberOfCopies):
		
			appendToName = ".copy" + str(i)

			translateVector = translateVector + translateVectorStep
			
			# loop through original bones
			for boneName in originalBoneNames:
				newBoneName = copyBone(arm.bones[boneName], appendToName)
				translateBone(arm.bones[newBoneName])
				copiedBones.append(newBoneName)
				print "duplicating: ",boneName," to: ", newBoneName	

		#connect the bones - set parents and options
		#loop through number of copies
		
		print
		print "Connecting bones and duplicating settings."
		print

		for i in range (0,numberOfCopies):
		
			appendToName = ".copy" + str(i)
			
			#loop through original bones		
			for boneName in originalBoneNames:
				newBoneName = boneName + appendToName
				connectBone(arm.bones[boneName], arm.bones[newBoneName], appendToName)

		#save changes
		arm.update()

		#make a list of the posebones
		pose = firstOb.getPose()
		
		print
		print "Duplicating constraints and pose mode settings for pose: ", pose
		print

		originalPoseBoneNames = []
		for poseBone in pose.bones.values():
			if dontCopy.count(poseBone.name) == 0:
				originalPoseBoneNames.append(poseBone.name)

				
		#make the armature editable
		arm.makeEditable()

		#copy the constraints
		#loop through number of copies
		for i in range (0,numberOfCopies):
		
			appendToName = ".copy" + str(i)
			
			#loop through original constraints
			#print "keys: ", originalConstraints.values()
			#print "values: ", originalConstraints.keys()

			#values = originalConstraints.values();		
			for poseBoneName in originalPoseBoneNames:
				newPoseBoneName = poseBoneName + appendToName
				copyConstraint(pose.bones[poseBoneName], pose.bones[newPoseBoneName], appendToName)

		#save changes
		arm.update()
		
		print
		print "bonecopy done"
		print

# Notes: It's a bit messy, I know.
# Would like to keep:
# Armature layers
# Pose mode things (locks, limits (tried that), custom objects, segments)
# Constraint influence
# 
# There may be some bugs, but it works for me. (Blender 2.42A, OSX / PPC, Python 2.4)

Hi…

Thats a pretty kewl tool…:wink:
Do u have a way to mirror it to the otherside as well???would help to create a spider.
Did u manage to duplicate the ik goals as well???
p.s:and is there a way can set it up in a button???

Thanks in advance
Nirmal David