10

I want to use the blender built-in skeleton as a character - is there a way to convert the bones to concretes meshes?enter image description here

LDCO
  • 581
  • 3
  • 19
  • 1
    I don't think so, but I believe a script could be created to represent the armature structure as a mesh... – m.ardito Mar 06 '17 at 17:08

1 Answers1

21

I was not able to find an addon for that and as it is very close from another question. Here is an operator to do that (nearly, as the bone shape is not exactly the same).

enter image description here

The code is commented below. To use it, copy the code in a text view and run the script.

Then in the 3D view, select your armature, hit space and type "MeshFromArmature" and validate.

The result is a rigged mesh mimicking the armature shape.

If you want to enhance the bone shape, the code is isolated in one function 'boneGeometry' with the needed parameters.

If the comments in the code are not clear enough, please tell.

2.79 Version

import bpy
import mathutils 
from mathutils import Vector 
from math import *

def CreateMesh():

obj = bpy.context.active_object

if obj == None:
    print( "No selection" )
elif obj.type != 'ARMATURE':
    print( "Armature expected" )
else:
    processArmature( bpy.context, obj )

#Create the base object from the armature def meshFromArmature( arm ): name = arm.name + "_mesh" meshData = bpy.data.meshes.new( name + "Data" ) meshObj = bpy.data.objects.new( name, meshData ) meshObj.matrix_world = arm.matrix_world.copy() return meshObj

#Create the bone geometry (vertices and faces) def boneGeometry( l1, l2, x, z, baseSize, l1Size, l2Size, base ): x1 = x * baseSize * l1Size z1 = z * baseSize * l1Size

x2 = x * baseSize * l2Size

z2 = z * baseSize * l2Size

x2 = Vector( (0, 0, 0) )
z2 = Vector( (0, 0, 0) )

verts = [
    l1 - x1 + z1,
    l1 + x1 + z1,
    l1 - x1 - z1,
    l1 + x1 - z1,
    l2 - x2 + z2,
    l2 + x2 + z2,
    l2 - x2 - z2,
    l2 + x2 - z2
    ] 

faces = [
    (base+3, base+1, base+0, base+2),
    (base+6, base+4, base+5, base+7),
    (base+4, base+0, base+1, base+5),
    (base+7, base+3, base+2, base+6),
    (base+5, base+1, base+3, base+7),
    (base+6, base+2, base+0, base+4)
    ]

return verts, faces

#Process the armature, goes through its bones and creates the mesh def processArmature(context, arm, genVertexGroups = True): print("processing armature {0}".format(arm.name))

#Creates the mesh object
meshObj = meshFromArmature( arm )
context.scene.objects.link( meshObj )

verts = []
edges = []
faces = []
vertexGroups = {}

bpy.ops.object.mode_set(mode='EDIT')

try:
    #Goes through each bone
    for editBone in [b for b in arm.data.edit_bones if b.use_deform]:
        boneName = editBone.name
        print( boneName )
        poseBone = arm.pose.bones[boneName]

        #Gets edit bone informations
        editBoneHead = editBone.head
        editBoneTail = editBone.tail
        editBoneVector = editBoneTail - editBoneHead
        editBoneSize = editBoneVector.dot( editBoneVector )
        editBoneRoll = editBone.roll
        editBoneX = editBone.x_axis
        editBoneZ = editBone.z_axis
        editBoneHeadRadius = editBone.head_radius
        editBoneTailRadius = editBone.tail_radius

        #Creates the mesh data for the bone
        baseIndex = len(verts)
        baseSize = sqrt( editBoneSize )
        newVerts, newFaces = boneGeometry( editBoneHead, editBoneTail, editBoneX, editBoneZ, baseSize, editBoneHeadRadius, editBoneTailRadius, baseIndex )

        verts.extend( newVerts )
        faces.extend( newFaces )

        #Creates the weights for the vertex groups
        vertexGroups[boneName] = [(x, 1.0) for x in range(baseIndex, len(verts))]

    #Assigns the geometry to the mesh
    meshObj.data.from_pydata(verts, edges, faces)

except:
    bpy.ops.object.mode_set(mode='OBJECT')
else:
    bpy.ops.object.mode_set(mode='OBJECT')

#Assigns the vertex groups
if genVertexGroups:
    for name, vertexGroup in vertexGroups.items():
        groupObject = meshObj.vertex_groups.new(name)
        for (index, weight) in vertexGroup:
            groupObject.add([index], weight, 'REPLACE')

#Creates the armature modifier
modifier = meshObj.modifiers.new('ArmatureMod', 'ARMATURE')
modifier.object = arm
modifier.use_bone_envelopes = False
modifier.use_vertex_groups = True

meshObj.data.update()

return meshObj

class MeshFromArmatureOperator(bpy.types.Operator): bl_idname = "wm.hello_world" bl_label = "MeshFromArmatureOperator"

def execute(self, context):
    CreateMesh()        
    return {'FINISHED'}

bpy.utils.register_class( MeshFromArmatureOperator )

2.8 Version

import bpy
import mathutils 
from mathutils import Vector 
from math import *

def CreateMesh():

obj = bpy.context.active_object

if obj == None:
    print( "No selection" )
elif obj.type != 'ARMATURE':
    print( "Armature expected" )
else:
    processArmature( bpy.context, obj )

#Create the base object from the armature def meshFromArmature( arm ): name = arm.name + "_mesh" meshData = bpy.data.meshes.new( name + "Data" ) meshObj = bpy.data.objects.new( name, meshData ) meshObj.matrix_world = arm.matrix_world.copy() return meshObj

#Create the bone geometry (vertices and faces) def boneGeometry( l1, l2, x, z, baseSize, l1Size, l2Size, base ): x1 = x * baseSize * l1Size z1 = z * baseSize * l1Size

x2 = x * baseSize * l2Size

z2 = z * baseSize * l2Size

x2 = Vector( (0, 0, 0) )
z2 = Vector( (0, 0, 0) )

verts = [
    l1 - x1 + z1,
    l1 + x1 + z1,
    l1 - x1 - z1,
    l1 + x1 - z1,
    l2 - x2 + z2,
    l2 + x2 + z2,
    l2 - x2 - z2,
    l2 + x2 - z2
    ] 

faces = [
    (base+3, base+1, base+0, base+2),
    (base+6, base+4, base+5, base+7),
    (base+4, base+0, base+1, base+5),
    (base+7, base+3, base+2, base+6),
    (base+5, base+1, base+3, base+7),
    (base+6, base+2, base+0, base+4)
    ]

return verts, faces

#Process the armature, goes through its bones and creates the mesh def processArmature(context, arm, genVertexGroups = True): print("processing armature {0}".format(arm.name))

#Creates the mesh object
meshObj = meshFromArmature( arm )
context.collection.objects.link( meshObj )

verts = []
edges = []
faces = []
vertexGroups = {}

bpy.ops.object.mode_set(mode='EDIT')

try:
    #Goes through each bone
    for editBone in [b for b in arm.data.edit_bones if b.use_deform]:
        boneName = editBone.name
        print( boneName )
        poseBone = arm.pose.bones[boneName]

        #Gets edit bone informations
        editBoneHead = editBone.head
        editBoneTail = editBone.tail
        editBoneVector = editBoneTail - editBoneHead
        editBoneSize = editBoneVector.dot( editBoneVector )
        editBoneRoll = editBone.roll
        editBoneX = editBone.x_axis
        editBoneZ = editBone.z_axis
        editBoneHeadRadius = editBone.head_radius
        editBoneTailRadius = editBone.tail_radius

        #Creates the mesh data for the bone
        baseIndex = len(verts)
        baseSize = sqrt( editBoneSize )
        newVerts, newFaces = boneGeometry( editBoneHead, editBoneTail, editBoneX, editBoneZ, baseSize, editBoneHeadRadius, editBoneTailRadius, baseIndex )

        verts.extend( newVerts )
        faces.extend( newFaces )

        #Creates the weights for the vertex groups
        vertexGroups[boneName] = [(x, 1.0) for x in range(baseIndex, len(verts))]

    #Assigns the geometry to the mesh
    meshObj.data.from_pydata(verts, edges, faces)

except:
    bpy.ops.object.mode_set(mode='OBJECT')
else:
    bpy.ops.object.mode_set(mode='OBJECT')

#Assigns the vertex groups
if genVertexGroups:
    for name, vertexGroup in vertexGroups.items():
        groupObject = meshObj.vertex_groups.new(name=name)
        for (index, weight) in vertexGroup:
            groupObject.add([index], weight, 'REPLACE')

#Creates the armature modifier
modifier = meshObj.modifiers.new('ArmatureMod', 'ARMATURE')
modifier.object = arm
modifier.use_bone_envelopes = False
modifier.use_vertex_groups = True

meshObj.data.update()

return meshObj

class MeshFromArmatureOperator(bpy.types.Operator): bl_idname = "wm.hello_world" bl_label = "MeshFromArmatureOperator"

def execute(self, context):
    CreateMesh()        
    return {'FINISHED'}

bpy.utils.register_class( MeshFromArmatureOperator )

Link to the blend file

Ray Mairlot
  • 29,192
  • 11
  • 103
  • 125
lemon
  • 60,295
  • 3
  • 66
  • 136
  • Would you be interested to submit this an official blender addon? – Fire Feb 13 '21 at 21:08
  • @Fire, currently I'm a bit out of all these. But if you think that's a good idea, feel free to do it (the code above is totally free to reuse ;) – lemon Feb 14 '21 at 06:51
  • For Blender 2.90 you must enable Developer Extras (User Preferences > Interface) so that "MeshFromArmature" will be searchable in the F3 menu. – Logic1 May 15 '22 at 12:57