Moving Meshes by a Bone in Python

Hi everybody,

I’m a French student and I had to work in Python for my studies.

I want to write a script which make move a mesh by Bone. So, I take a blender file with an Human inside. To try, I draw 3 Bones to make the arm move. Each are child of parent of another, in the same armature. After that, I link these Bones to parts of my Mesh. When I turn my 3D view in “Pose Mode”, I can control the arm of my “mannequin” by moving its Bones. For the moment, everything is OK. But my problem is when I want to reproduce the movements of the Bones made with my mouse in a Python script.

With the “Python scripting reference” in the Blender Help I found the Class and the Module which let me to command the Bones and the Amrmature. When I run the script I wrote, it move the bone as I’ve write (good point) but the meshes doesn’t come with (bad point), even I’m in “Pose Mode”. So I think I don’t use the good instructions…

My code :

import Blender
from Blender import Armature
from Blender.Mathutils import *

armatures = Armature.Get()
arm = armatures.values()[0]
arm.makeEditable()
eb = Armature.Editbone()
eb = arm.bones["Bone.001"]
eb.head = (1, 1, 1)
arm.update()

Hello, as I mentioned to you elsewhere (I’m mentioning it here for the benefit of other users), your problem is that you are accessing the base bone data through edit mode. You will need to work with the pose data. The documentation and an example can be found here:
http://www.blender.org/documentation/243PythonDoc/Pose-module.html

Post if you have any more questions!

Levi

OK, thanks. I’ll see if it work :wink: .

Also try
Window.RedrawAll()

because if it works in the GUI and doesn’t when you do the same thing with a script, it might simply be because the GUI didn’t refresh.

:stuck_out_tongue:

Thanks, but it doesn’t work because the code I tryed change the position of the meshes but in edit mode. So it’s normal that nothing move.

I think the solution is in the link posted by reD_Fox, but I have a problem with an instruction :

arm_ob = scn.objects.new(arm_data)

I work with Blender 2.43 and Python 2.4.4 and the error returned is

Can you try to copy the beginning of the code and see if it work? Because this error is strange (Blender seems not to know this inbstruction).

Hmm. The code works for me, although if you’re wanting to manipulate existing armatures, the code you should be interested in is further down in the example.

Basically, you need to get an armature Object (see the Object module reference section for ways to do this), which is what your trouble line is attempting to do (add the armature data to the scene and return a reference to its object). Once you have the armature Object, you call getPose() to work with the pose data. This happens in the example code after “pose = arm_ob.getPose()”.

Levi

OK, I had just forgott bracketts. But I have another problem. For pose = arm_ob.getPose()[i] not send me back [i]None I have to delete and redraw all of my Bones with the script. But the problem is that he draw me the Bones twice, with a simmetry on the X axis. When I copy the code which make the Bones move, only one group of bone move and don’t make my meshes move. The other group can make move my meshes but don’t react with the script. Have you the same problem?

My script :


import Blender
from Blender import *

scn = Scene.GetCurrent()
armatures = Armature.Get()
arm_data = armatures.values()[0]
print arm_data
arm_ob = scn.objects.new(arm_data)
arm_data.makeEditable()
ebones = [Armature.Editbone(), Armature.Editbone(), Armature.Editbone()]
del arm_data.bones["Bone.002"]
del arm_data.bones["Bone.001"]
del arm_data.bones["Bone"]
arm_data.update()
arm_data.makeEditable()
ebones[0].name = "Bone"
ebones[1].name = "Bone.001"
ebones[2].name = "Bone.002"

for eb in ebones:
    arm_data.bones[eb.name] = eb
    
ebones[0].head = Mathutils.Vector(-0.1, 0.927, -13.474)
ebones[0].tail = Mathutils.Vector(0.635, 0.49, -13.955)
ebones[1].head = Mathutils.Vector(0.635, 0.49, -13.955)
ebones[1].tail = Mathutils.Vector(1.417, 0.201, -14.234)
ebones[2].head = Mathutils.Vector(1.417, 0.201, -14.234)
ebones[2].tail = Mathutils.Vector(1.827, 0.1, -14.36)

ebones[1].parent = ebones[0]
ebones[2].parent = ebones[1]

arm_data.update()

pose = arm_ob.getPose()

act = arm_ob.getAction()
if not act:
    act = Armature.NLA.NewAction()
    act.setActive(arm_ob)

xbones = arm_ob.data.bones.values()
pbones = pose.bones.values()

frame = 1
for pbone in pbones:
    pbone.quat[:] = 1.000,0.000,0.000,0.0000
    pbone.insertKey(arm_ob, frame, Object.Pose.ROT)

pbones[0].quat[:] = 1.000,0.1000,0.2000,0.20000
pbones[1].quat[:] = 1.000,0.6000,0.5000,0.40000
pbones[2].quat[:] = 1.000,0.1000,0.3000,0.40000

frame = 25
for i in xrange(3):
    pbones[i].insertKey(arm_ob, frame, Object.Pose.ROT)

pbones[0].quat[:] = 1.000,0.000,0.000,0.0000
pbones[1].quat[:] = 1.000,0.000,0.000,0.0000
pbones[2].quat[:] = 1.000,0.000,0.000,0.0000


frame = 50      
for pbone in pbones:
    pbone.quat[:] = 1.000,0.000,0.000,0.0000
    pbone.insertKey(arm_ob, frame, Object.Pose.ROT)

Yikes! I’m not quite sure exactly what you’re trying to do, but if you already have your armature created, you don’t need the first part of the example script.
Step 1 - Get the armature object.
The easiest (but not necessarily the best) way to do this is to select the armature before running the script, and then get the armature object with Object.GetSelected()[0].

Step 2 - Get the pose data from the armature object.
Do this like “pose = arm_ob.getPose()”.

Step 3 - Modify the pose data.
This is a bit more complicated. Read through the pose module documentation, and study the examples. In addition to using actions (probably the best way) you can modify the bones’ matrices. Someone else will have to help you with this stuff, though, since I have never used it (matrices or actions).

Using the example’s code on an existing, selected armature, your code should be something like this:


import Blender
from Blender import *

arm_ob = Object.GetSelected()[0]

pose = arm_ob.getPose()

act = arm_ob.getAction()
if not act:
    act = Armature.NLA.NewAction()
    act.setActive(arm_ob)

xbones = arm_ob.data.bones.values()
pbones = pose.bones.values()

frame = 1
for pbone in pbones:
    pbone.quat[:] = 1.000,0.000,0.000,0.0000
    pbone.insertKey(arm_ob, frame, Object.Pose.ROT)

pbones[0].quat[:] = 1.000,0.1000,0.2000,0.20000
pbones[1].quat[:] = 1.000,0.6000,0.5000,0.40000
pbones[2].quat[:] = 1.000,0.1000,0.3000,0.40000

frame = 25
for i in xrange(3):
    pbones[i].insertKey(arm_ob, frame, Object.Pose.ROT)

pbones[0].quat[:] = 1.000,0.000,0.000,0.0000
pbones[1].quat[:] = 1.000,0.000,0.000,0.0000
pbones[2].quat[:] = 1.000,0.000,0.000,0.0000


frame = 50      
for pbone in pbones:
    pbone.quat[:] = 1.000,0.000,0.000,0.0000
    pbone.insertKey(arm_ob, frame, Object.Pose.ROT)

Levi

Don’t be affraid if I said I love you but… I LOVE YOU!!!

The last thing I’ve to do is to search how to view in my “3D View” the position of my bones in a selected frame…

It’s ok, I find it; But I have another problem. I serach to redefine the “Rest position” of my Armature but I don’t find the button or script to do that. If anyone have an idea, he is welcome ^^.

EDIT : I go open a new toppic

Sorry for the tripple post…

I have a new problem. That’s with the quaternions. I want to do my rotations in the Blender’s axis but the references of this rotations are others axis :
Xquat = Ybled+ 2pi/3
Yquat = Zblend
Zqaut = Xblend+2
pi/3
Please, how to do to have the true axis of blender ?