How would I do this? (Has to do with shape keys)

Ok, I’m working on a VTA exporter. That’s VerTex Animation. It allows games using the source engine(link)to do facial animation. It does this by using shape keys(morph targets, whatever your program calls them). My problem is that shape keys store EVERY VERTEX, but I only need the changed ones. So, how would I go about just getting the changed ones?

Thanks

Simply iterate all vertices for each shape and compare the .co attribute. Check the API Docs for more info

Im sorry, I’m still pretty new to python. Could you tell me what the .co attribute is? I can’t find it in the docs.

http://www.blender.org/documentation/248PythonDoc/

Sorry i have a cold and i am not on my desktop now. What you are looking for is the “Key” module. Not shure if you can simply do myobject.key to get it. The key has a list of blocks, each representing a shape. Then you can use getData() to get the vertex data.

Ya, I’ve got the getdata() to get the verts, and I have a test script to print them out using the .x, .y, and .z positions. But I haven’t seen anything about a .co

EDIT:Ignore the text below, I’m dumb and it works as it should.

EDIT:
Also, why doesn’t this work? I have a pop up menu that gives the name of all the shape keys and an option “all”, which would do all of them. When I press “All”, it does set all_list up right(I know this by forcing all_list to be printed) but all_sel for some reason doesn’t get set, and thus it prints out some error about shapenames out of range or something. But it should be going to the print with all_list shouldn’t it?


    all_sel = 0
    if shapenames[choice-1] == "All":
                all_sel = 1
                all_list = [b.name for b in me.key.blocks]
    if all_sel:
                print "Writing %s:" % all_list
    else:
                print "Writing %s:" % shapenames[choice-1]

EDIT1: I need to take a new approach. It seems that getdata() just returns vectors.

How would I set the active shape key in blender through python? I’ve noticed that the active shape key can be accessed like a mesh.

EDIT2: Ok, I see how to set the active shape key, with object.activeshape=number. But the screen doesn’t update to reflect the newly selected key until I go into and out of edit mode. How would I tell blender to update the screen?
Hmmm, I can do it as:


        object.activeShape=choice
        Blender.Window.EditMode(1)
        Blender.Window.EditMode(0)

But there has to be a better way.

Also, Is it just me, or is the blender python api impossible to go through for a newbie? I’m having so much trouble finding what I need.

EDIT3: Wow, why has noone told me about the interactive python scripter built in to Blender. That thing is awesome and will help me A LOT.

Ignore the text and code below. I’m reworking my approach. I’m just gonna leave it here though.

Ok, how would I go about getting the normal of the vertex? If I can get that, I can probably finish this up.

Here’s my code so far. It won’t work for you, as it is a part of another exporter. I’m adding vta functionality to it. I know the coding that I did in it sucks, but I just started learning python the other day.
I use bits of code out of http://blenderartists.org/forum/showthread.php?t=162747 , I hope lonewolfarcher doesn’t mind.

Right now I have it so when you select the VTA option in the exporter, it asks for a filename. Then it gives a pop-up menu with a list of all the shape keys and an option for all of them. When you select something, it prints out the verts of the shape key you selected to the command line.


class VtaExport ( BaseExport ):
    def __init__( self ):
        BaseExport.__init__( self )
    def getExportFilename( self, filename ):
            return filename[: -( len( filename.split( '.', -1 )[ -1 ] ) + 1 ) ] + '.vta'
    def main( self ):
        Blender.Window.EditMode(0)
        oblist=Blender.Object.GetSelected()
        if len(oblist)!=1:
            Blender.Draw.PupMenu("Error: Select a single object.")
        object=oblist[0]
        shapeIndex=object.activeShape
        me=object.getData(mesh=1)
        n=len(me.verts)
        if not me.key:
            Blender.Draw.PupMenu("Mesh doesn't have any Shape Keys")
            return False
        km=len(me.key.blocks)
        nameList=[]
        blocknames = ""
        for block in me.key.blocks[0:km]:
            nameList.append(block.name)
            blocknames+="|"+block.name
        nameList.append("All")
        blocknames+="|All"
        choice = Blender.Draw.PupMenu("Select Shape Key%t"+blocknames)
        all_sel = 0
        if choice>0:
            if nameList[choice-1] == "All":
                all_sel = 1
                all_list = [b.name for b in me.key.blocks]
            if all_sel:
                print "Writing %s:" % all_list
            else:
                print "Writing %s:" % nameList[choice-1]
        numtouse = 1
        if all_sel:
            numtouse = len(nameList)-1
            choice = 1
        while numtouse:
            numtouse -=1
            blockverts = me.key.blocks[choice-1]
            keyverts=blockverts.getData()
            print "
 Writing %s:" % nameList[choice-1]
            for j in range(n):
                print "%f , %f , %f" % (keyverts[j].x, keyverts[j].y, keyverts[j].z)
            choice += 1
        return False

    def Export( self, filename):
        error = self.main()
        if error:
             Blender.Draw.PupMenu("Error%t|"+error)
        print "Nothing yet. :'("

I really have no idea what I’m doing here…

Just wanna tell you guys that I did figure out how to do it, and have nearly completed my exporter. I get shape key data by changing the objects active shape, and the accessing that like a mesh.

Example:


mainkeyverts=[]
object.activeShape=0
Blender.Window.EditMode(1)
Blender.Window.EditMode(0)
objdata1=object.getData(mesh=1)
for j1 in range(len(objdata1.verts)):
      mainkeyverts.append(objdata1.verts[j1].co*1)

That gets me a list of the verts in the first shape key(the one that needs to be unchanged) for comparing. The annoying thing was I didn’t know I needed to multiply the vert by 1 to actually PUT it in the list, and not just link it to the mesh. That was ticking me off when mainkeyverts was changing every time I changed the active shape.

Then I just looped through all the shape keys, setting the objects active shape and comparing the verts in them to the ones in mainkeyverts.

This is what, my 4th post in a row? Quadruple post. But I’m just putting this here to help me remember this, and maybe help someone else.

You see, I needed to have both a bone selected AND my object, and be able to switch that object into and out of edit mode, so my change to the activeShape would take effect. This would only work when the object and bone were selected in a special order, if even then. Most people who would be using the exporter would not have the IQ to do that. So I had to come up with something new.

I found out I could see the modifiers on the object with “object.modifiers”. But that didn’t help me too much until I found out I could also access the object in the armature modifier like so:


"bones=object.modifiers[j][Modifier.Settings.OBJECT]"

Where “j” is the index of the armature modifier. Then I just use “getData()” on bones, and I can have access to the objects armature. I don’t have to worry about multiple armature modifiers being on the object, so this should work fine. And it will still let me use the “activeShape” way of getting shape keys, as the bones will never selected to screw up my accessing them.

EDIT: I FIGURED IT OUT. I guess I should have done a little research first. I need to use:
“mod.getitem(Blender.Modifier.Settings.OBJECT)”
To get the object name, it works now.

Ok, I think this is my last question I have regarding this. How would I iterate through the modifiers and get the Object attached to one of them? This is what I have tried:


        armature = -1
        onearmature = 1
        mods=object.modifiers
        for mod in mods:
            if mod.type == 8 and onearmature:
                onearmature = 0
                print "%s" % mod
                armature=mod[Modifier.Settings.OBJECT]

It gets to the part “armature=mod[Modifier.Settings.OBJECT]”, and then complains with “NameError: global name ‘Modifier’ is not defined”.

How would I do this? Wouldn’t mod be equal to “object.modifiers[j]”, where j is an index. So shouldn’t I just be able to tack on the part to get the object? I don’t understand why it doesn’t work.

What the hell? Look at some output I got in the interactive scripter:


cube=bpy.data.objects["Cube"] 
a=cube.modifiers 
for b in a:c=b[Modifier.Settings.OBJECT] 
c 
[Object "aaa"]

It’s working fine there, but not in my other code?
Is it because its being called from in a class?

EDIT: Let me clarify my question:
Ok, I have my exporter working. But there is just one thing. When someone loads up a “.blend”, they first have to manually change the current shape key at least once before I can have access to the objects “activeShape”. Is there a way to do it without needing them to do anything?

The way I access shape key data is like this:


object.activeShape=keynum
Blender.Window.EditMode(1)
Blender.Window.EditMode(0)

Then I can just access the object like a mesh and have the shape key data.
But for some reason, the change won’t ever happen unless they have manually changed the current shape key at least once since loading the file.

What can I do?

I can’t help with avoiding the manual refresh, but the prospect of a Source exporter that handles shapekeys has got me on the edge of my seat!

EDIT:

Have you raided #blendercoders@freenode yet?

No, I haven’t been there yet. I will check it out.

BTW: The exporter will be released in this thread(link). It’s a modification of Dvondrakes SMD exporter. I fixed his SMD exporting and now I have implemented VTA exporting. I plan on releasing it tomorrow whether or not I find a way to automatically fix my problem. (The one linked to in the bottom of his first post is just the fixed SMD exporting.)

EDIT: Hmmm, for the amount of people there, it is awfully slow. In the hour an a half since I put a question in #blendercoders, there has been no talk or anything. My question is still the most recent thing there…maybe I’ll get a response in the morning.

I found a work around. Blender is quite strange. I mean, when the user had messed with the shape keys, it would work just fine. But when they haven’t, it just won’t update in object mode, AND there’s no way in blender to set a shape keys value through python, to force it to show the key in this situation(In Blender 2.5 this will be possible, right? You’ll have access to everything.).

I just leave it in edit mode to access the data. For some reason, blender updates the mesh according to shape key while in edit mode, even if it won’t in object mode…Ugh, hopefully 2.5 won’t have all these problems.

Expect a release some time tomorrow.

Here it is, have fun! :smiley:
http://filesmelt.com/downloader/smd_vta_export.zip
Remember, I just added VTA exporting to this and fixed a bug in SMD exporting. The SMD part was mainly made by someone who goes by dvondrake.
If you look through the file, my code starts close to the bottom. It’s surrounded by "##########"s
Also remember I just started learning python 4-5 days ago, so the VTA exporter part of that file is a big mess.

You know what’s funny? I don’t even plan on using this. I just saw that there was no VTA exporter for Blender, and I decided to add VTA exporting to the SMD exporter. Man, this must have taken like a combined 30+ hours over the past 4-5 days. I had to learn Python and then learn, mostly through trial and error, all the Blender stuff.

I was AFK for the last week, but I’m definitely going to do some work with this; I’ve had a couple of TF2 mod projects stalled due to the lack of shapekeys > VTA exporting.

A million thanks, windwakr!

Don’t worry about talking to yourself on the board, I do it all the time. It helps me thinks and work things out. It is a great paper trail for others who may follow your path.:slight_smile: