0
$\begingroup$

I want to add an empty to each vertex of my model but sometimes it works and sometimes there's an error ("Requires selected vertices or active vertex group"). However this error appears after the loop is running the 10th time or so; So, this is completely confusing...

Where's the problem with my code?

import bpy

#CREATE GROUP FOR STICKY EMPTIES
bpy.ops.group.create(name="sticky_grp")

#ACTIVE OBJECT
actObj = bpy.context.active_object

#VERTICE ARRAY OF THE ACTIVE OBJECT
actVerts = actObj.data.vertices

#COUNT FOR NAMESPACES IN LOOP
cnt = 0

#FOR LOOP TO GET VERTICES AND SET "a" AS VERTEX VARIABLE
for a in actVerts:

    bpy.ops.object.mode_set(mode='OBJECT')                   #SWITCH TO OBJECT MODE
    a.select = True                                          #SELECT VERTEX
    bpy.ops.object.mode_set(mode='EDIT')                     #SWITCH TO EDIT MODE
    bpy.ops.object.hook_add_newob()                          #CREATE HOOK TO SELECTED   VERTEX
    bpy.context.selected_objects[0].name = "sticky_empty"    #RENAME EMPTY TO STICKY EMPTY
    bpy.ops.mesh.select_all(action='DESELECT')               #DESELECT VERTICES

    #SELECT STICKY EMPTY
    try:
        if cnt == 0:
            bpy.data.objects['sticky_empty'].select
            bpy.ops.group.objects_add_active(group = 'sticky_grp')

        elif 1 <= cnt < 10:
            bpy.data.objects['sticky_empty.00' + str(cnt)]
            bpy.ops.group.objects_add_active(group = 'sticky_grp')

        elif 10 <= cnt < 100:
            bpy.data.objects['sticky_empty.0' + str(cnt)]
            bpy.ops.group.objects_add_active(group = 'sticky_grp')

        else:
            bpy.data.objects['sticky_empty.' + str(cnt)]
            bpy.ops.group.objects_add_active(group = 'sticky_grp')
    except:
        print("SELECT STICKY EMPTY ERROR")  


    #DELETE HOOK MODIFIER
    try:
        if cnt == 0:
            bpy.ops.object.modifier_remove(modifier="Hook-Empty")

        elif 1 <= cnt < 10:
            bpy.ops.object.modifier_remove(modifier="Hook-Empty.00" + str(cnt))

        elif 10 <= cnt < 100:
            bpy.ops.object.modifier_remove(modifier="Hook-Empty.0" + str(cnt))

        else:
            bpy.ops.object.modifier_remove(modifier="Hook-Empty." + str(cnt))
    except:
        print("DELETE HOOK MODIFIER ERROR") 

    #ADD NAMESPACE + 1         
    cnt = cnt + 1 
    print(a)
$\endgroup$
2
  • $\begingroup$ I want to update an addon by myself otherwise i would do this manually but i have to do this without any other addons $\endgroup$ Oct 19 '14 at 16:18
  • $\begingroup$ That looks like the error when all vertices are selected by none of them are active. This can happen when nothing is selected and then you use 'a' to select everything. There is a tool called Select->'Side Of Active' that has a problem like this. If this is the case here then make sure that one of the vertices is active and highlighted yellow. $\endgroup$ Oct 20 '14 at 7:02
3
$\begingroup$

You have to toggle out of edit mode after deselecting all vertices to solve your issue.

bpy.ops.object.mode_set(mode='OBJECT')          #SWITCH TO OBJECT MODE
a.select = True                                 #SELECT VERTEX
bpy.ops.object.mode_set(mode='EDIT')            #SWITCH TO EDIT MODE 
bpy.ops.object.hook_add_newob()
bpy.ops.mesh.select_all(action='DESELECT')      #DESELECT VERTICES
bpy.ops.object.editmode_toggle()                

For better understanding why you have to leave the edit mode this answer maybe helps.


Edit: In terms of better error handling I suggest you to write a bit more functional and split the code in useful pieces. The positive side effect would be that you have much more control, because you also can cache your states. I assume from the code above you want to have following functions:

  • create empties from all verticies of the selected object
  • add and assign hook modifiers for all empties to the selected object
  • create a group or add empties to a group

For e.g. this function creates the empties and returns a list of the new ones:

# -----------------------------------------------------------------------
# create empties from vertices
# -----------------------------------------------------------------------
# parameter: mesh object
# returns: list of new empty objects

def createEmptiesFromVerts (obj):

    # get object data
    objMesh = obj.data
    vertList = [vert for vert in objMesh.vertices]

    # create a list for the new empties
    emptyList = []

    for i in range(len(vertList)):

        # get local coordinate
        vertCoordinate = obj.data.vertices[i].co
        vertCoordinate = obj.matrix_world * vertCoordinate

        # add the empty    
        bpy.ops.object.add(type='EMPTY', location=vertCoordinate)
        newEmpty = bpy.context.active_object
        newEmpty.location = vertCoordinate
        newEmpty.empty_draw_size = newEmpty.empty_draw_size # / 4
        bpy.ops.object.select_all(action='TOGGLE')
        bpy.ops.object.select_all(action='DESELECT')

        # append the new empty to the list
        emptyList.append(newEmpty)

    # set object to original state
    bpy.context.scene.objects.active = obj
    obj.select = True

    # return the new empties  
    return emptyList

With this incoming list you can go on with the next function and assign the hook modifiers.

# -----------------------------------------------------------------------
# create hook modifiers
# -----------------------------------------------------------------------
# parameter: mesh object, hook object list
# returns: assigned hooks list, assigned modifier list

def hooksFromVerts (obj, hookObjs):

    # get object data
    objMesh = obj.data
    vertList = [vert for vert in objMesh.vertices]

    # create list to save all assigned hooks
    assignedHooks = []
    assignedModifiers = []

    for i in range(len(vertList)):

        bpy.ops.object.mode_set(mode="EDIT")
        bpy.ops.mesh.select_all(action="DESELECT")
        bpy.context.tool_settings.mesh_select_mode = (True , False , False)
        bpy.ops.object.mode_set(mode="OBJECT")

        # get local coordinate of vertex
        vertCoordinate = obj.data.vertices[i].co
        vertCoordinate = obj.matrix_world * vertCoordinate

        bpy.context.object.data.vertices[i].select = True
        bpy.ops.object.mode_set(mode="EDIT")

        # assign hook if coords of vert and hook object are equal
        for n in hookObjs:
            if vertCoordinate == n.location:
                #modifierName = "Hook" + str(i+1)
                modifierName = "Hook_" + n.name
                obj.modifiers.new(modifierName, type='HOOK')
                obj.modifiers[modifierName].object = n
                bpy.ops.object.hook_assign(modifier=modifierName)

                # append the hook objects to the list
                assignedHooks.append(n)

                # append modifiers
                assignedModifiers.append(modifierName)

    # set object to original state    
    bpy.ops.mesh.select_all(action = 'DESELECT')
    bpy.ops.object.mode_set(mode ="OBJECT")

    # set object to original state
    bpy.context.scene.objects.active = obj
    obj.select = True

    # return assogned hooks objects and modifiers
    return assignedHooks, assignedModifiers

As last step you can create a function that creates a group if it not exists and throw your empties in it. To call this is much more easier and for us more readable at all:

# get the object
selectedObj = bpy.context.active_object

if selectedObj.type == 'MESH':

    # create empties
    generatedEmpties = createEmptiesFromVerts(selectedObj)

    # create hooks
    generatedHooks = hooksFromVerts(selectedObj, generatedEmpties)

    # remove modifiers
    #removeModifiersByNameList(selectedObj, generatedHooks[1])

    # create or add to group
    generatedGroup = addObjectsToGroup("testgroup", generatedHooks[0])

else:
    print ("please select a mesh object.")

Hope this helps!

$\endgroup$
2
  • $\begingroup$ Hm this didnt work but i found out that when i go into edit mode before running the script and select one vertex and then go to object mode and run the script it works... but this is not the sense... i dont get it $\endgroup$ Oct 20 '14 at 13:48
  • $\begingroup$ My Testsetup was a Cube in Objectmode (Blender 2.70a) - works fine. Can you specify your setup? And please specify what is not worḱing for you. $\endgroup$
    – p2or
    Oct 20 '14 at 14:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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