7
$\begingroup$

I'm using blender 2.72b x64 on windows 7.

I need a quick way to render armature using f12 button. With shadows and everything. "render armature" means render geometry that is visible in viewports - boxes/octahedrons/sticks, depending on chosen visualization.

I only need to render still frames, no animation.

"OpenGL render image" is not an option, because OpenGL render does not produce raytraced shadows.

As I understand it, this can be done by either somehow turning armature into renderable geometry or generating mesh from it via script.

Is there a built-in way to do it or ready to use script somewhere?

$\endgroup$
  • $\begingroup$ Not a duplicate, because opengl render does not render shadows. $\endgroup$ – SigTerm Nov 8 '14 at 15:56
  • 2
    $\begingroup$ AFAIK there is no built in way to do it, but a script probably wouldn't be too hard. Not sure if one exists or not though.. $\endgroup$ – gandalf3 Nov 8 '14 at 20:10
  • $\begingroup$ @gandalf3: Sigh... it's been 2 or 3 years since I wrote last blender exporter in python. Guess I'll get to writing the script if nobody has a snippet to share (I'll post it here if I finish it). I've been used armature+rigify as wooden manikins for 2d drawing reference and lighting/shadows for a rough idea which light goes where. Works perfectly with exception of armature being invisible in render window. $\endgroup$ – SigTerm Nov 8 '14 at 22:33
8
$\begingroup$

Blender doesn't support rendering armatures directly.

This is intentional and there is no plan to add support for this feature. ~ @ideasman42


However, I've come up with script to convert armature into mesh or skin.

Implemented as blender addon, only BBone armature style is supported (bezier bones, subdivided bones etc are untested).

Creates mesh if armature in "pose" mode. Creates SKIN if armature is in "skin" mode.

armature_to_mesh.py

bl_info = {"name": "Armature To Mesh", "category": "Object"}

import bpy
import mathutils

class ArmatureToMesh(bpy.types.Operator):
    """Armature to mesh/skin conversion script"""
    bl_idname = "object.armature_to_mesh_skin"
    bl_label = "Armature to Mesh/Skin"
    bl_options = {'REGISTER', 'UNDO'}

    def decomposeMatrix(self, matrix):
        return [x.to_3d() for x in matrix.transposed()]

    def processArmature(self, context, arm, genVertexGroups = True):
        print("processing armature {0}".format(arm.name))

        if genVertexGroups:
            #because setting pose_position ot 'REST' manually doesn't work for some reason.
            genVertexGroups = arm.data.pose_position == 'REST'

        meshName = arm.name + "_mesh"
        meshData = bpy.data.meshes.new(meshName + "Data")
        meshObj = bpy.data.objects.new(meshName, meshData)
        meshObj.location = arm.location

        scene = context.scene
        scene.objects.link(meshObj)

        armMatrix = arm.matrix_local.copy()

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


        for bone in arm.pose.bones:
            poseBone = bone
            boneName = bone.name
            armBone = arm.data.bones[boneName]
            #print(poseBone.matrix)
            #print(armBone.matrix)
            #print(boneName)

            boneMatrix = poseBone.matrix
            boneStart = poseBone.head
            boneEnd = poseBone.tail

            decomposedMatrix = self.decomposeMatrix(boneMatrix)
            #print(decomposedMatrix)
            xSize = armBone.bbone_x
            zSize = armBone.bbone_z
            #print(xSize, zSize)
            xSizeAdd = bone.x_axis
            zSizeAdd = bone.z_axis
            xSizeAdd = decomposedMatrix[0]
            zSizeAdd = decomposedMatrix[2]
            ySizeAdd = decomposedMatrix[1]
            origin = mathutils.Vector((0.0, 0.0, 0.0)) * boneMatrix
            xSizeAdd *= xSize
            zSizeAdd *= zSize
            ySizeAdd *= bone.length

            baseIndex = len(verts)

            verts.append((boneStart - xSizeAdd + zSizeAdd)*armMatrix)
            verts.append((boneStart + xSizeAdd + zSizeAdd)*armMatrix)
            verts.append((boneStart - xSizeAdd - zSizeAdd)*armMatrix)
            verts.append((boneStart + xSizeAdd - zSizeAdd)*armMatrix)
            verts.append((boneEnd - xSizeAdd + zSizeAdd)*armMatrix)
            verts.append((boneEnd + xSizeAdd + zSizeAdd)*armMatrix)
            verts.append((boneEnd - xSizeAdd - zSizeAdd)*armMatrix)
            verts.append((boneEnd + xSizeAdd - zSizeAdd)*armMatrix)

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

            if genVertexGroups:
                vertexGroups[boneName] = [(x, 1.0) for x in range(baseIndex, len(verts))]

        meshData.from_pydata(verts, edges, faces)

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

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

        meshData.update()

        return meshObj

    def processObject(self, context, obj):
        if (obj == None):
            return False
        if (obj.type != "ARMATURE"):
            print ("invalid type {0} of object {1}: armature expected".format(obj.type, obj.name))
            return False
        self.processArmature(context, obj)
        return True

    def execute(self, context):
            scene = context.scene
            selected = context.selected_objects
            processedAnything = False
            if len(selected) > 0:
                print ("selected objects present, processing selection")
                for obj in selected:
                    processedAnything |= self.processObject(context, obj)
                pass
            else:
                print ("processing active object")
                obj = context.active_object
                processedAnything |= self.processObject(context, obj)

            if not processedAnything:
                print ("no objects processed")

            return {'FINISHED'}

def register():
    bpy.utils.register_class(ArmatureToMesh)

def unregister():
    bpy.utils.unregister_class(ArmatureToMesh)

##register()

Armature-to-skin in action. Screenshot

$\endgroup$
  • $\begingroup$ sorry I am new to Blender...how can I use your Python script for rendering? $\endgroup$ – user14004 Apr 26 '15 at 15:33
  • $\begingroup$ see this answer running-python-script-in-blender $\endgroup$ – Chebhou Apr 26 '15 at 15:47
  • $\begingroup$ Yeah, actually I meant...what the script really does? how can i launch it in order to obtain the armature meshes? $\endgroup$ – user14004 Apr 26 '15 at 16:40
  • 1
    $\begingroup$ @Gennosuke: Armature does not have a mesh. So you can't "obtain" it. The script should be placed into "addons" folder (google how to install addons for blender). It creates new (renderable) object and attaches it to armature. You need to select armature, press "space", start typing "armature", select "Armature to Mesh/Skin" and that will create renderable object. If armature is in "pose" mode, it will be mesh that won't move with armature. If armature is in "skin" mode, it will be skinned mesh that'll be attached to armature. Only boxed representation of armature is supported. $\endgroup$ – SigTerm Apr 28 '15 at 14:07
  • $\begingroup$ Thanks for the add-on, found by searching for a way to render bones in Blender, but this is useful for more than just that. $\endgroup$ – user16810 Aug 31 '15 at 6:00

protected by Community Aug 31 '15 at 6:53

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

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