I want to use the blender built-in skeleton as a character - is there a way to convert the bones to concretes meshes?
1 Answers
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).
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 )
- 29,192
- 11
- 103
- 125
- 60,295
- 3
- 66
- 136
-
-
@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
