3
$\begingroup$

I am sure this is a very simple thing to do. But because of my inexperience, I am having trouble with it. I havent gotten much from reading the blender python api. The answer was probably right in my face, but I just didnt know what to do. I just want to know how to make a script that exports weight values to a text file. As well as bone elements - like the rotation matrix (3x3 mat) the children of the bone and the offset of the bone. Oh and also the vertexGroups (like the vertices that each bone influences).

$\endgroup$
  • $\begingroup$ And if there is another 3d modelling software that can do this (without the use of scripting), you can suggest it to me. But i would rather stick to blender at the moment. I am to deep to abandon it. Plus recommending another 3d modelling software on a blender website would be quite disrespectful $\endgroup$ – Kunta-Kinte Feb 26 '17 at 7:10
3
$\begingroup$

While the answer is in Blender's API docs, the relationships aren't clearly spelt out so you need to "get" some of the relationships to know how it fits together.

An armature can get confusing, there are EditBones that define the armature that you see in edit mode. Then you have PoseBones that are used when posing the bones in an animation.

You access EditBones through bpy.data.armatures['Armature'].edit_bones or while the armature is in edit mode with object.data.edit_bones, while you will find PoseBones in object.pose.bones.

While an EditBone does have a matrix property that combines the location and rotation of the bone, it relies mostly on the head, tail and roll properties of each bone and doesn't keep any rotation properties. The PoseBones use the head as the origin and then the rotation_mode to determine whether the rotation_euler, rotation_axis_angle or the rotation_quaternion property is used.

Both EditBones and PoseBones have a children property to list any children the bone may have.

An object has a list of it's vertex_groups and each vertex group has an index number.

A mesh object's data includes a list of it's vertices and each of these vertices has a groups property that lists the groups that the vertex is associated with. This list contains the group index (which matches the vertex group index above) and the weight used for each group. The group weight is the same value you edit using weight painting.

When an armature deforms a mesh it finds vertices that use a group with the same name as the bone and uses the weight to define how much to influence the vertex.

So while looping through the armature bones, using the bone name you can get the vertex group index for the bone, then get the vertices it influences.

import bpy

arm = bpy.data.objects['Armature']
obj = bpy.data.objects['Cube']

obj_verts = obj.data.vertices
obj_group_names = [g.name for g in obj.vertex_groups]

for bone in arm.pose.bones:
    if bone.name not in obj_group_names:
        continue

    gidx = obj.vertex_groups[bone.name].index

    bone_verts = [v for v in obj_verts if gidx in [g.group for g in v.groups]]

    for v in bone_verts:
        w = v.groups[gidx].weight
        print('Vertex',v.index,'has a weight of',w,'for bone',bone.name)
$\endgroup$
  • $\begingroup$ A question: is it more efficient to look for bone's vertices for each bone (like in your code here) or to loop for all vertices and check if each vertex correspond to one of the wanted bones names (or indexes)? $\endgroup$ – lemon Feb 26 '17 at 10:29
  • 1
    $\begingroup$ A simple reverse of the loops as above would get similar times. While there are other things you can do that can change performance, you would expect extra memory use from generating all the data before you start exporting. This way can export the data as it finds it. $\endgroup$ – sambler Feb 26 '17 at 11:20
  • $\begingroup$ This is the same person who asked the question btw. How does one export the bone data as well. Like the offset, children, and rotation matrix. $\endgroup$ – dothingsilike Mar 3 '17 at 22:46
  • $\begingroup$ The for loop is going through each bone, you can find the names of all the properties here. Add steps to export each bone data to the loop. $\endgroup$ – sambler Mar 4 '17 at 12:08
0
$\begingroup$

The sambler's answer worked to me, but I had to add a condition in the loop:

 for v in bone_verts:
    for g in v.groups:
       if g.group == gidx: 
          w = g.weight
          print('Vertex',v.index,'has a weight of',w,'for bone',bone.name)

Because when you access to the items of v.groups, the indices are not the same as the gidx indices. The indices gidx are the indices bones without taking into account those bones that do not affect any vertex and the indices of v.groups start from 0 to 6-9 at most, the items of v.groups are the bones that affect to this vertex v. You go through the items of v.groups searching for the item that has the same index group (accessing for example through v.groups[0].groups to get the value of gidx)

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.