1
$\begingroup$

what this script should do is add 1-3 little cubes to each side of a specific object (torus in my case for testing). then for each cube a random face within a section of the torus gets choosen and the upper 4 vertices of the cube are getting moved to the vertices of that face and a hook is applied. so far it's working for one side, but as i modify the function for the other side by adding arguments, blender crashes. i am almost sure to say this is due to memory issues. i am not into memory handling in python at all, therefore i tried del for every variable at the end of the function, sadly without success. so how do i free enough memory? or is there another approach? sorry if this code is hard to look at.. i'm a beginner. edit: hope i got the indentation right now

import bpy
import bmesh
import random

# Delete old objects
for ob in bpy.context.scene.objects:
ob.select = ob.type == 'MESH' and ob.name.startswith("Cube")
bpy.ops.object.delete()

def addcube(name,bxtop,bxlow,posneg,v1,v2,v3,v4): 
    # Deselect everything
    bpy.data.objects['Torus'].select = True
    bpy.context.scene.objects.active = bpy.data.objects['Torus']
    bpy.ops.object.mode_set(mode = 'EDIT') 
    bpy.ops.mesh.select_all(action = 'DESELECT')
    bpy.ops.object.mode_set(mode = 'OBJECT')

    # Cube creation
    bpy.context.scene.cursor_location = (0.0, 0.0, 0.0)

    # set +- x,y-axis
    xco = random.randint(20,60)
    xco = (posneg * xco) / 10
    yco = random.randint(0,30)
    yco = (yco / 10) - 1

    ccverts = ((-0.2 + xco,-0.2 + yco,0), (0,0,1), (1,0,1), (0.2 + xco,-0.2 + yco,0), (-0.2 + xco,0.2 + yco,0), (0,1,1), (1,1,1), (0.2 + xco,0.2 + yco,0))

    ccfaces = ((0,1,2,3), (0,4,5,1), (4,5,6,7), (2,6,7,3), (3,7,4,0))

    ccmesh = bpy.data.meshes.new(name)

    ccobject = bpy.data.objects.new(name, ccmesh)

    ccmesh.from_pydata(ccverts, [], ccfaces)
    ccmesh.update(calc_edges=True)

    ccobject.location = bpy.context.scene.cursor_location
    bpy.context.scene.objects.link(ccobject)


    # Get the coordinates of the first vertices of 'Mapping' object
    firstObjData = bpy.context.scene.objects['Torus'].data
    bm1 = bmesh.new()
    bm1.from_mesh(firstObjData)

    # Set 'Mapping' object active
    bpy.data.objects['Torus'].select = True
    bpy.context.scene.objects.active = bpy.data.objects['Torus']

    # Store all Mapping verts locations
    allvertlocsx = []
    for v in bm1.verts:
        v.co.xyz * bpy.data.objects['Torus'].matrix_world
        allvertlocsx.append(v.co.x)
    allvertlocsy = []
    for v in bm1.verts:
        v.co.xyz * bpy.data.objects['Torus'].matrix_world
        allvertlocsy.append(v.co.y)
    allvertlocsz = []
    for v in bm1.verts:
        v.co.xyz * bpy.data.objects['Torus'].matrix_world
        allvertlocsz.append(v.co.z)  

    # Bounding settings (adjustable)
    xtop = max(allvertlocsx) - bxtop
    ytop = max(allvertlocsy) - 0.5
    ztop = max(allvertlocsz) - 0.02
    xlow = min(allvertlocsx) + bxlow
    ylow = min(allvertlocsy) + 0.5
    zlow = min(allvertlocsz) + 0.02

    possiblevertsx = set()
    for v in bm1.verts:
        if v.co.x <= xtop:
            if v.co.x >= xlow:
                possiblevertsx.add(v.index)

    possiblevertsy = set()
    for v in bm1.verts:
        if v.co.y <= ytop:
            if v.co.y >= ylow:
                possiblevertsy.add(v.index)

    possiblevertsz = set()
    for v in bm1.verts:
        if v.co.z <= ztop:
            if v.co.z >= zlow:
                possiblevertsz.add(v.index)

    setverts = []        
    for v in (possiblevertsx & possiblevertsy & possiblevertsz):
        setverts.append(v)

    # Selected verts in poll
    for int in setverts:
        bm1.verts[int].select = True

    linkfaces = []    
    for v in bm1.verts:
        if v.select:
            for f in v.link_faces:
                linkfaces.append(f.index)

    # Set the coordinates of the first vertices of 'Cube' object
    secondObjData = bpy.context.scene.objects[name].data
    bm2 = bmesh.new()
    bm2.from_mesh(secondObjData)

    # Get random face
    f_index_max = len(linkfaces) - 1

    while True:
        randlinkindex = random.randint(0,f_index_max)
        randface = linkfaces[randlinkindex]

        bpy.ops.object.mode_set(mode = 'EDIT')
        bm1.select_mode = {'FACE'}
        bm1.faces[randface].select_set(True)

        # Get random face verts
        randfaceverts = []
        for v in bm1.faces[randface].verts:
            randfaceverts.append(v.index)

        # Update            
        firstObjData.update()
        bpy.ops.object.mode_set(mode = 'OBJECT')
        bm1.to_mesh(firstObjData)

        # Convert local coorinates to world coordinates before assignment
        vertCoordinates1 = bpy.data.objects['Torus'].matrix_world * bm1.verts[randfaceverts[2]].co.xyz
        vertCoordinates2 = bpy.data.objects['Torus'].matrix_world * bm1.verts[randfaceverts[3]].co.xyz
        vertCoordinates3 = bpy.data.objects['Torus'].matrix_world * bm1.verts[randfaceverts[0]].co.xyz
        vertCoordinates4 = bpy.data.objects['Torus'].matrix_world * bm1.verts[randfaceverts[1]].co.xyz

        # Convert world coorinates to local coordinates before assignment
        bm2.verts[v1].co.xyz = bpy.data.objects[name].matrix_world.inverted() * vertCoordinates1 
        bm2.verts[v2].co.xyz = bpy.data.objects[name].matrix_world.inverted() * vertCoordinates2 
        bm2.verts[v3].co.xyz = bpy.data.objects[name].matrix_world.inverted() * vertCoordinates3 
        bm2.verts[v4].co.xyz = bpy.data.objects[name].matrix_world.inverted() * vertCoordinates4 

        bm2.to_mesh(secondObjData)

        # Trigger viewport update
        bpy.context.scene.objects.active = bpy.context.scene.objects.active

        # Loop break + max face angle
        if bm2.verts[5].co.z > bm2.verts[6].co.z:
            if (bm2.verts[5].co.x - 0.05) <= bm2.verts[6].co.x:
                break

    # Set cursor position
    bpy.context.scene.cursor_location = bpy.data.objects[name].matrix_world * bm2.verts[1].co.xyz

    # make sure everything is deselected before selecting vertex for hook
    bpy.data.objects[name].select = True
    bpy.context.scene.objects.active = bpy.data.objects[name]
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action="SELECT")
    bpy.ops.mesh.normals_make_consistent()
    bpy.ops.mesh.select_all(action="DESELECT")
    bpy.context.tool_settings.mesh_select_mode = [True, False, False] # (Vertex,Edge,Face)

    # select vertex, add hook, rename to Hook1
    bpy.data.objects['Torus'].select = True
    bpy.data.objects[name].select = True
    bmesh.from_edit_mesh(bpy.context.object.data).verts[1].select = True
    bmesh.from_edit_mesh(bpy.context.object.data).verts[2].select = True
    bmesh.from_edit_mesh(bpy.context.object.data).verts[5].select = True
    bmesh.from_edit_mesh(bpy.context.object.data).verts[6].select = True
    bpy.ops.object.hook_add_selob()
    bpy.ops.object.mode_set(mode='OBJECT', toggle=False)

    # Save xco and randface for comparison
    addcube.xcoords = xco
    addcube.randomface = randface

"""
_______________

Function calls:
_______________

"""

"""
left side
"""

# Cube    
addcube('Cube',2.2,0,-1,1,5,6,2)
save_cube = (addcube.xcoords,addcube.randomface)  

# Cube2
condition2 = random.randint(0,1)
if condition2 == 1:
    addcube('Cube2',2.2,0,-1,1,5,6,2)
    save_cube2_list = [addcube.xcoords,addcube.randomface]  
    while ((save_cube2_list[0] - 0.5) <= save_cube[0] <= (save_cube2_list[0] + 0.5)) or (save_cube[1] == save_cube2_list[1]):   
        bpy.ops.object.select_all(action='DESELECT')
        bpy.data.objects['Cube2'].select = True
        bpy.ops.object.delete()       
        addcube('Cube2',2.2,0,-1,1,5,6,2)
        save_cube2_list = [addcube.xcoords,addcube.randomface]

     # Confirm Cube2
     save_cube2 = (addcube.xcoords,addcube.randomface)

# Cube3
condition3 = random.randint(0,1)
if condition3 == 1:
    if condition2 == 1:
         addcube('Cube3',2.2,0,-1,1,5,6,2)
         save_cube3_list = [addcube.xcoords,addcube.randomface]
         while ((save_cube3_list[0] - 0.5) <= save_cube[0] <= (save_cube3_list[0] + 0.5)) or (save_cube[1] == save_cube3_list[1]) or ((save_cube3_list[0] - 0.5) <= save_cube2[0] <= (save_cube3_list[0] + 0.5)) or (save_cube2[1] == save_cube3_list[1]):     
            bpy.ops.object.select_all(action='DESELECT')
            bpy.data.objects['Cube3'].select = True
            bpy.ops.object.delete()    
            addcube('Cube3',2.2,0,-1,1,5,6,2)
            save_cube3_list = [addcube.xcoords,addcube.randomface]

        # Confirm Cube3
        save_cube3 = (addcube.xcoords,addcube.randomface)
    else:
        addcube('Cube2',2.2,0,-1,1,5,6,2)
        save_cube2_list = [addcube.xcoords,addcube.randomface]  
        while ((save_cube2_list[0] - 0.5) <= save_cube[0] <= (save_cube2_list[0] + 0.5)) or (save_cube[1] == save_cube2_list[1]):   
            bpy.ops.object.select_all(action='DESELECT')
            bpy.data.objects['Cube2'].select = True
            bpy.ops.object.delete()       
            addcube('Cube2',2.2,0,-1,1,5,6,2)
            save_cube2_list = [addcube.xcoords,addcube.randomface]

        # Confirm Cube2
        save_cube2 = (addcube.xcoords,addcube.randomface)    

"""
right side
"""

# Cube4    
addcube('Cube4',0,2.2,1,5,6,1,2)
save_cube4 = (addcube.xcoords,addcube.randomface)  

# Cube5
condition5 = random.randint(0,1)
if condition5 == 1:
    addcube('Cube5',0,2.2,1,5,6,1,2)
    save_cube5_list = [addcube.xcoords,addcube.randomface]  
    while ((save_cube5_list[0] - 0.5) <= save_cube4[0] <= (save_cube5_list[0] + 0.5)) or (save_cube4[1] == save_cube5_list[1]):   
        bpy.ops.object.select_all(action='DESELECT')
        bpy.data.objects['Cube5'].select = True
        bpy.ops.object.delete()       
        addcube('Cube5',0,2.2,1,5,6,1,2)
        save_cube5_list = [addcube.xcoords,addcube.randomface]

    # Confirm Cube5
    save_cube5 = (addcube.xcoords,addcube.randomface)

# Cube6
condition6 = random.randint(0,1)
if condition6 == 1:
    if condition5 == 1:
        addcube('Cube6',0,2.2,1,5,6,1,2)
        save_cube6_list = [addcube.xcoords,addcube.randomface]
        while ((save_cube6_list[0] - 0.5) <= save_cube4[0] <= (save_cube6_list[0] + 0.5)) or (save_cube4[1] == save_cube6_list[1]) or ((save_cube6_list[0] - 0.5) <= save_cube5[0] <= (save_cube6_list[0] + 0.5)) or (save_cube5[1] == save_cube6_list[1]):     
            bpy.ops.object.select_all(action='DESELECT')
            bpy.data.objects['Cube6'].select = True
            bpy.ops.object.delete()    
            addcube('Cube6',0,2.2,1,5,6,1,2)
            save_cube6_list = [addcube.xcoords,addcube.randomface]

        # Confirm Cube6
        save_cube6 = (addcube.xcoords,addcube.randomface)
    else:
        addcube('Cube5',0,2.2,1,5,6,1,2)
        save_cube5_list = [addcube.xcoords,addcube.randomface]  
        while ((save_cube5_list[0] - 0.5) <= save_cube4[0] <= (save_cube5_list[0] + 0.5)) or (save_cube4[1] == save_cube5_list[1]):   
            bpy.ops.object.select_all(action='DESELECT')
            bpy.data.objects['Cube5'].select = True
            bpy.ops.object.delete()       
            addcube('Cube5',0,2.2,1,5,6,1,2)
            save_cube5_list = [addcube.xcoords,addcube.randomface]

        # Confirm Cube5
        save_cube5 = (addcube.xcoords,addcube.randomface)  

enter image description here

$\endgroup$
  • $\begingroup$ if your indentation is broken: edit your question, delete your code, paste the properly indented code, and indent it by pressing Ctrl+K (with all code lines selected). or link to a gist - don't be lazier than you need to be.. $\endgroup$ – zeffii Jan 28 '16 at 15:09
  • $\begingroup$ here's the link to the previous version without the implementation to do the same thing for the right side: gist.github.com/anonymous/224c9b1401788a584ae5 $\endgroup$ – e-proxy Jan 28 '16 at 15:46
  • $\begingroup$ You must be using a version of blender that is older than 2.73 else you would be getting ensure_lookup_table errors. Maybe this helps you (i'm not saying this is how I would code this..) but with a few modifications it runs on Blender 2.76 gist.github.com/zeffii/4d3bec9c16c7a6b05b0e $\endgroup$ – zeffii Jan 28 '16 at 16:29
  • $\begingroup$ it's worth updating to Blender 2.76 - because several potential crashes in scripted BMesh manipulations were fixed since your version was released ( 2.71) $\endgroup$ – zeffii Jan 28 '16 at 16:33
  • $\begingroup$ thanks a million! can't test it right now but i guess you answered my question $\endgroup$ – e-proxy Jan 29 '16 at 16:50
1
$\begingroup$

i finally found the solution to my problem. i had a while loop that was set for outdated testing purposes, wich ran infinitely for the right side. thanks zeffii for pointing out updated blender gets ensure_lookup_table errors.

$\endgroup$

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.