shape keys

Hey all,

I’ve been searching for info on creating / modifying shape keys through python, but I haven’t turned up anything. Is it possible? I’d like to automake some baseline changes I need to make to some shapes and I was hoping I could save myself some trouble in the long run as well.

Thanks in advance.

please delete this post

I would suggest getting in contact with toloban. He keeps all his shapes in a text file somehow and I think he uses python to get them back and forth. Send him a PM and he should be able to point you in the right direction

Currently, access to shape keys is read-only, you can however append new shape keys using the insertKey() method in NMesh.
http://www.blender3d.org/documentation/242PythonDoc/NMesh.NMesh-class.html#insertKey

Instead of a single update() you use something like this:


mesh.update()
mesh.insertKey()
mesh.update()

You can then assigning a new name like this


mesh.key.blocks[-1].name = newname
mesh.update()

There seems to be a bug that creates shape keys in the wrong order when using scripts, hopefully this will be corrected after a report that was submitted.

Thank you so much :slight_smile:
I got, for the moment, done what with a script I later found. But I will definately try to make my own script for custom changes. Again, thanks a lot :slight_smile:

I get a strange error :confused:


myOb = Blender.Object.GetSelected()
p_paste = myOb[0].getData(mesh=1)
p_paste.insertKey()
AttributeError: 'Blender Mesh' object has no attribute 'insertKey'

Final script. The script copies the shape of the first object and pastes it in the second object + makes a new Shape key:

#!BPY

import Blender
from Blender import *

myOb = Blender.Object.GetSelected()
c_copy = myOb[1].getData(mesh=1)
p_paste = myOb[0].getData(mesh=1)

v_count = 0

for vert in c_copy.verts:
v_count += 1

for vv in range(v_count):
p_paste.verts[vv].co = c_copy.verts[vv].co
p_paste.verts[vv].no = c_copy.verts[vv].no

pp_paste = myOb[0].getData()
pp_paste.update()
pp_paste.insertKey()
pp_paste.update()

Great Code
Thanks Thanks

Looks like this one :
http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_rvk1versrvk2_en.htm

(already in the Blender’s bundle scripts )

Just an observation: If the target object has no shape keys yet, your script will overwrite the basis key. Your script should check whether pp_paste.key is None, in which case you have to append another key (to become basis) before modifying the mesh.

So you already figured out insertKey() is not in Mesh module. There is also insertShapeKey() for objects, but it is not explained how to use it:
http://www.blender3d.org/documentation/242PythonDoc/Object.Object-class.html#insertShapeKey

Thanks for the advice! Now the script checks first if there is an existing base key:

#!BPY

""" Registration info for Blender menus: <- these words are ignored
Name: 'Copy/Paste into ShapeKey'
Blender: 242a
Group: 'Object'
Tip: 'Copy mesh shape into 2nd selected obj + insert a new ShapeKey'
"""

__author__ = "René Yanagida aka Daredemo"
__version__ = "1.0 2006/11"

__bpydoc__ = """\
"Copy/Paste into ShapeKey" copies vertice locations of all verts of 1st object to the 2nd object and inserts a new Shape Key for the 2nd object.

Usage:

Select the object with the shape you want to add to the 2nd object as a Shape Key. Run this script from the "Object->Scripts" menu of the 3d View.
"""

import Blender
from Blender import *

myOb = Blender.Object.GetSelected()
c_copy = myOb[1].getData(mesh=1)
p_paste = myOb[0].getData(mesh=1)
X_paste = myOb[0].getData()

if not X_paste.key:
    X_paste.insertKey()
    X_paste.update()


v_count = 0

for vert in c_copy.verts:
        v_count += 1

for vv in range(v_count):
    p_paste.verts[vv].co = c_copy.verts[vv].co
    p_paste.verts[vv].no = c_copy.verts[vv].no

pp_paste = myOb[0].getData()
pp_paste.update()
pp_paste.insertKey()
pp_paste.update()

http://projects.blender.org/tracker/?group_id=9&atid=127&func=detail&aid=3663
:slight_smile:

What’s new in this version:

  1. You can select any number of objects (including your lamps and camera, the script is wise enough to ignore objects that are not mesh objects)
  2. All selected mesh objects will be used to create shape keys for the last mesh object (i.e., if you choose 4 mesh objects the 4th object will get 3 new shapes)
  3. However, if you choose to copy/paste only selected verts, the new shapes will be “sequential/cumulative” at this point
  4. Error messages if incorrect number of (mesh) objects are selected or if the last object is not a mesh object
  5. Popup menu
  6. Now the two scripts are build into one
#!BPY

""" Registration info for Blender menus: <- these words are ignored
Name: 'Copy/Paste verts into Shape Key(s)'
Blender: 242a
Group: 'Object'
Tip: 'Copy mesh shape(s) of selected object(s) into last mesh object as (a) new Shape Key(s)'
"""

__author__ = "René Yanagida aka Daredemo"
__version__ = "1.0 2006/11"

__bpydoc__ = """\
"Copy/Paste verts into Shape Key(s)" copies vertice locations of SELECTED objects (either location of all verts or selected verts) into the last object and inserts (a) Shape Key(s)

Usage:

Select the mesh object(s) that will be used as (a) Shape Key(s) for the last mesh object. You can copy/paste either the locations of all vertices or only the location(s) or selected vert(s). IMPORTANT: if you select more than two mesh objects, selected vertices will be treated as sequencial data! Use the script from the "Object->Scripts" menu of the 3d View.
"""

import Blender
from Blender import *

text = "Which vertices to Copy/Paste?%t|ONLY SELECTED vertices|ALL vertices"
result = Blender.Draw.PupMenu(text)

if result <> -1:
 myOb = Blender.Object.GetSelected()

 o_count = 0
 m_count = 0
 for myMh in myOb:
  o_count += 1
  if myMh.getType() == "Mesh":
   m_count += 1

 if m_count < 2:
  myErr1 = "ERROR!%t|Select at least two MESH objects"
  Blender.Draw.PupMenu(myErr1)
 else:
  if myOb[0].getType() <> "Mesh":
   myErr2 = "ERROR!%t|Last select object is NOT a MESH objects"
   Blender.Draw.PupMenu(myErr2)
  else:
   p_paste = myOb[0].getData(mesh=1)
   X_paste = myOb[0].getData()

   if not X_paste.key:
    X_paste.insertKey()
    X_paste.update()

   for a_ob in range(1, o_count):
    if myOb[a_ob].getType() == "Mesh":
     c_copy = myOb[a_ob].getData(mesh=1)

     v_count = 0

     for vert in c_copy.verts:
      v_count += 1

     for vv in range(v_count):
      if result == 1:
       if c_copy.verts[vv].sel:
        p_paste.verts[vv].co = c_copy.verts[vv].co
        p_paste.verts[vv].no = c_copy.verts[vv].no
      else:
       p_paste.verts[vv].co = c_copy.verts[vv].co
       p_paste.verts[vv].no = c_copy.verts[vv].no


     pp_paste = myOb[0].getData()
     pp_paste.update()
     pp_paste.insertKey()
     pp_paste.update()