Script(s) needed for BlenRig 3.0

Hi guys! For those who don´t know what BlenRig 3.0 is, it is a free rig for blender that has muscle simulation and lots of other features. You can check it out at www.jpbouza.com.ar.

Among its capabilities, the rig is able to stretch and bake the stretched pose into Edit Mode thanks to the Armature Baker script made by Bart Crouch. So, with the rig you can create new characters, or easily adjust its proportions for a new model.

Now, the thing is that the new muscle system is based on geometric muscles that are attached to the armature in several ways (Armature modifier and Mesh Deform modifier).

So, the first thing that the script should do would be:

1)Check if the selected objects have Armature or Mesh Deform modifiers
2)make a copy of the modifiers and hit the ¨apply¨ button in the original modifier.

Well, that would be one script, I don´t know if it is possible to do such a thing in python though…

The second script is simpler I think, it would be intended for mirroring the muscles, so that you only have to edit one half of the system. This is what the script should do:

1)Mirror the selected objects in x axis of the world coordinates
2) It should mirror all the shapekeys of the objects too (and maybe recalculate the normals?)
3)Mirror the names of the bones assigned as drivers of the shapekeys.

Well, that would be it.

Thanks a lot!!

Regarding the first script: unfortunately it isn’t currently possible to hit the ‘apply’ or the ‘copy’ button with python. There is a workaround though by getting the deformed mesh data, removing the modifiers and switching the old mesh data with the deformed data.
However I’m not completetely certain why you want to copy the old modifiers. Wouldn’t that mean that you deform the mesh twice?

About the second script: this is actually harder than the first script imho. It would be a great help if you could provide a simplified sample .blend with a setup on which you’d like the script to operate. So just a few bones with only just a few drivers and shapekeys. This allows us to better understand the situation. Speaking for myself, I usually don’t work with bones driving shapekeys (I’m just a simple blender user ;)), so a simplified sample .blend would clarify a lot.

Below you can find a script that applies all Armature and MeshDeform modifiers of the active object. Any other modifiers aren’t affected. (script request 1, if I’m not mistaken)

import bpy
import Blender
from Blender import *

# check if everything is ok and return the modifiers that have to be applied
def initialise():
    scn = bpy.data.scenes.active
    ob = scn.objects.active
    if not ob:
        return False
    if ob.type == 'Mesh':
        if len(ob.modifiers)>0:
            mods = []
            for mod in ob.modifiers:
                if mod.type in [Modifier.Types.ARMATURE, Modifier.Types.MESHDEFORM]:
                    mods.append(mod)
            if len(mods)==0:
                return False
            editmode = Window.EditMode()
            if Window.EditMode():
                Window.EditMode(0)
            return [editmode, ob, mods]
        return False
    else:
        return False

# apply the modifiers
def main((editmode, ob, mods)):
    me = ob.getData(mesh = True)
    realtime = [mod[Modifier.Settings['REALTIME']] for mod in ob.modifiers]
    for mod in ob.modifiers:# if mod not in mods, somehow doesn't work
        mod[Modifier.Settings['REALTIME']] = False # temporarily disable modifiers
    for mod in mods: 
        mod[Modifier.Settings['REALTIME']] = True
    me.getFromObject(ob.name) # derived mesh data, based on the chosen modifiers
    for i in range(len(ob.modifiers)): # re-enable all modifiers
        ob.modifiers[i][Modifier.Settings['REALTIME']] = realtime[i]
    for mod in mods: # remove the modifiers that have been applied
        ob.modifiers.remove(mod)
    ob.makeDisplayList()
    Window.EditMode(editmode)
    Window.RedrawAll()

init = initialise()
if init:
    main(init)

Pretty long script for such a simple task. Fortunately Blender 2.5 will allow us to push the ‘apply’ button with python, so this code won’t be needed anymore.

I can’t tell from the license if I am allowed to use your rig for commercial purposes?

Hi Atom, yes you can use it for commercial purpose. The only restriction that the license has is that if you are going to share the rig, you have to share it the same way I do and you also have to credit me for making the original file, that means that you can modify it, but you can’t sell it. But of course you can use it and make pictures and movies, and you can sell those pictures and movies. The actual restriction is with the source file, but not with the artwork that you can do.

Hey Crouch!!! Thanks man, I’m gonna test that script right away!!!

Crouch! The works, but unfortunately it kills all the shapekeys of the object. Also, the script should first copy the modifiers, then apply the original ones and leave the new ones alone…

This may be too hard now, besides, the script is intended for people that is really lazy, heheh, that is not my case, I don’t mind hitting the apply button in a few objects…Don’t worry about this, maybe in 2.5 we’ll be able to work something out!!

Thanks a lot!!

Blender starts complaining to me when I want to apply an armature modifier or a meshdeform modifier on a mesh that has shapekeys. It’s even impossible to do so with Blender’s regular UI.
To mimic the copy-button in Blender simply remove these two lines from the script I posted:

    for mod in mods: # remove the modifiers that have been applied
        ob.modifiers.remove(mod)

About the second script: care to give a small sample file so it’s easier to come up with a script?

Thanks a lot Bart!!

It is not possible to apply Modifiers when the object has shpekeys, that´s right.

I´ve attached the Armature with the biceps muscles. You should erase one of the muscles, and by running the script over the muscle that is left, you should obtain an object that is an exact copy of the msucle you deleted.

http://www.jpbouza.com.ar/downloads/SecondScript.blend

The main thing the script should do is:
_to mirror the object in the world X axis. As the object has shapekeys, you have to manually mirror each of the shapekeys in Edit Mode.

_ Then, It should mirror the Bone Dirvers of the Shapekeys

_It should also mirror the vertex groups of the object.

Now, the naming of the bones of the rig has¨the ¨left¨ and ¨right¨ convention, I don´t know if that could be a problem. If you need me to change the naming to ¨.l¨ and ¨.r¨ for some Python restriction just tell me!

Some very bad news: it’s currently impossible to do this.
I started coding it, but the current python api doesn’t allow to set (or get) the driver bone. It only provides access to the driver object, but if the object is an armature and you wish to use a bone, you can’t.
Since 2.49 was the last 2.4x of Blender, I’m afraid you’ll have to wait until Blender 2.5. Unless you’re somehow able to get the feature request implemented in 2.49a, but as far as I know that’ll be a bug-fix only release. I’m sorry :(.

Thanks Bart!! Don´t worry!! We´ll see what we can do in 2.5!!

Thanks a million!

There is a workaround. The trick is to define drivers as pydrivers and set the curve’s driverExpression property with the mirror script.

tolobán: that might actually work. I’ll take a look at it.

tolobán’s proposal was good, but the problem remains. Because even though I could use a python expression to set a correct driver, I have no means of getting the bone name that should drive it.
Below you can find a script that does everything requested except from setting the driver (should be at line 88).

import bpy
import Blender
from Blender import *

def init(ob_src, scn):
    if ob_src.type != 'Mesh':
        return False
    me_src = ob_src.getData(mesh=True)
    newname = mirrorName(ob_src.name)
    if not newname:
        return false
    try:
        ob_tar = bpy.data.objects[newname]
    except:
        ob_tar = newObject(newname, scn)
    if ob_tar.type != 'Mesh':
        ob_tar = newObject(newname, scn)
    me_tar = ob_tar.getData(mesh=True)
    me_tar.verts = None
    for group in me_tar.getVertGroupNames():
        me_tar.removeVertGroup(group)
    return [ob_src, me_src, ob_tar, me_tar]

def newObject(newname, scn):
    me = bpy.data.meshes.new(newname)
    ob = scn.objects.new(me)
    return ob
    
def mirrorName(name):
    if 'left' in name:
        mirror = name.replace('left', 'right')
    elif 'right' in name:
        mirror = name.replace('right', 'left')
    else: return False
    return mirror
    
def main((ob_src, me_src, ob_tar, me_tar)):
    # add vertices
    me_tar.verts.extend([v.co for v in me_src.verts])
    # add faces
    me_tar.faces.extend([[v.index for v in f.verts] for f in me_src.faces])
    # smooth faces as necessary
    for i in range(len(me_tar.faces)):
        me_tar.faces[i].smooth = me_src.faces[i].smooth
    # copy and mirror vertgroups
    for group in me_src.getVertGroupNames():
        groupname = mirrorName(group)
        if not groupname:
            groupname = group
        me_tar.addVertGroup(groupname)
        for i in me_src.getVertsFromGroup(group, 1):
            # this isn't optimal, but function doesn't allow list input for weights
            me_tar.assignVertsToGroup(groupname, [i[0]], i[1], Mesh.AssignModes.ADD)
    # copy the shapekeys
    key_src = me_src.key
    if key_src:
        relative = key_src.relative
        blocks = key_src.blocks
        # for each shapekey
        for b in blocks:
            # copy locations
            locs = b.data
            for i in range(len(me_tar.verts)):
                me_tar.verts[i].co = locs[i]
            ob_tar.insertShapeKey()
            # copy other settings
            key_tar = me_tar.key
            key_tar.relative = relative
            newblock = key_tar.blocks[-1]
            newblock.name = b.name
            if relative:
                newblock.slidermax = b.slidermax
                newblock.slidermin = b.slidermin
                newblock.vgroup = b.vgroup
        # copy the ipo of the shapekey
        ipo_src = key_src.ipo
        if ipo_src:
            ipo_tar = Ipo.New('Key', ".".join(ipo_src.name.split('.')[:-1]))
            key_tar.ipo = ipo_tar
            for c_src in ipo_src.curves:
                c_tar = ipo_tar.addCurve(c_src.name)
                for bp in c_src.bezierPoints:
                    c_tar.append(bp)
                c_tar.extend = c_src.extend
                c_tar.interpolation = c_src.interpolation
                c_tar.sel = c_src.sel
                # driver settings
                ### THIS IS WHERE THE PROBLEM IS ###
            
    # assign material to mesh
    me_tar.materials = me_src.materials
    # set matrix of object
    ob_tar.setMatrix(ob_src.matrix)
    # mirror on x-axis
    ob_tar.size = (-ob_tar.size[0], ob_tar.size[1], ob_tar.size[2])
    # copy modifiers
    ob_tar.modifiers = ob_src.modifiers

def control():
    editmode = Window.EditMode()
    Window.EditMode(0)
    scn = bpy.data.scenes.active
    selection = scn.objects.selected
    for sel in selection:
        start = init(sel, scn)
        if not start:
            continue
        main(start)
    scn.update() # makes the armature modifier behave properly
    Window.EditMode(editmode)
    Window.RedrawAll()

control()

Wow Crouch thanks a million!!

I´ll try it out!!

Did you try the script “deformed mesh to rvk” released with blender ?

Hey jms thanks, but that script doesn´t do what I need! :wink:

Crouch! Here is a file with the muscles from one side of the rig. The problem I see with the script is that it seems to use the center of the objects as pivoting point, is it possible to use the World X 0.0 as the mirroring plane, or at least use the cursor as the pivoting point?

If it is not possible I´ll try to change the centers of the muscles objects to 0 and re assign the shapekeys. (This problem is my fault anyway)

About the first script, it works great, but the object loses its material, I see that the second script has some material lines, would those lines make the trick in the first script too?

Hi,
I’ll have a look at both issues, but it’ll have to wait till after the weekend (the weather is too good to sit inside behind my computer ;)).

About the first script: yes, the materials can be kept.

import bpy
import Blender
from Blender import *

# check if everything is ok and return the modifiers that have to be applied
def initialise():
    scn = bpy.data.scenes.active
    ob = scn.objects.active
    if not ob:
        return False
    if ob.type == 'Mesh':
        if len(ob.modifiers)>0:
            mods = []
            for mod in ob.modifiers:
                if mod.type in [Modifier.Types.ARMATURE, Modifier.Types.MESHDEFORM]:
                    mods.append(mod)
            if len(mods)==0:
                return False
            editmode = Window.EditMode()
            if Window.EditMode():
                Window.EditMode(0)
            return [editmode, ob, mods]
        return False
    else:
        return False

# apply the modifiers
def main((editmode, ob, mods)):
    me = ob.getData(mesh = True)
    realtime = [mod[Modifier.Settings['REALTIME']] for mod in ob.modifiers]
    for mod in ob.modifiers:# if mod not in mods, somehow doesn't work
        mod[Modifier.Settings['REALTIME']] = False # temporarily disable modifiers
    for mod in mods: 
        mod[Modifier.Settings['REALTIME']] = True
    mat = me.materials
    me.getFromObject(ob.name) # derived mesh data, based on the chosen modifiers
    me.materials = mat
    for i in range(len(ob.modifiers)): # re-enable all modifiers
        ob.modifiers[i][Modifier.Settings['REALTIME']] = realtime[i]
    #for mod in mods: # remove the modifiers that have been applied
    #    ob.modifiers.remove(mod)
    ob.makeDisplayList()
    Window.EditMode(editmode)
    Window.RedrawAll()

init = initialise()
if init:
    main(init)

I’m still looking into mirroring on the world x-axis. It should be possible using some matrix transformations, but I’m still working on it (my matrix knowledge isn’t very big).

Thanks Crouch I´ll try the first script when I get home today!

About the other script, don´t go crazy with the x rotation, I should re center those objects anyway…

Bart, I finally had the time to try these scripts!! They work really well!! (saving the Ipo Driver copying impossibility)
Don´t worry about the mirroring in the World X-Axis, I am recentering the muscle objects now (I should have done that from the beginning…)

One thing though, you see this last script, the one that applies the Armature and Mesh Deform Modifier, could it be possible to add the functionality of copying the shapekeys so that they can be preserved?? It would be similar to the muscle mirroring script only that instead of mirroring, it applies the Armature and Mesh deform modifier and preserves the shapekeys with the Ipos and everything.

Thanks!!