I want to make animation in blender 2.8 by using premade stl files. I do that by importing the stls frame by frame. See code below.
In order to save memory I delete the old object before I load a new stl. This goes well for a few frames. Then a EXCEPTION_ACCESS_VIOLATION error is thrown during the Dependency Graph evaluation.
I guess I’m not deleting objects at the best time. Any ideas when to delete the old objects in my usecase? Maybe I should delete objects using another of the bpy.app.handlers?
# delete old object created at previous frame
for o in bpy.data.objects:
if surfacename in o.name:
o.parent = None
bpy.data.objects.remove(o, do_unlink=True,do_ui_user=True)
# import new object from stl for current frame
timedir = scene.frame_current
stlfilename=os.path.join(bpy.context.scene["datadir"],timedir,surfacename+'.stl')
bpy.ops.import_mesh.stl(filepath=stlfilename)
# get object with newly loaded stl
obnew=[o for o in bpy.context.scene.objects if o.select_get()][0]
# adjust position of newly imported stl
origo=bpy.data.objects['rocketparent']
obnew.parent = origo
obnew.matrix_world = mathutils.Matrix.Translation([0,0,1.5]) @ origo.matrix_world
# link newly loaded object to scene
bpy.context.scene.collection.objects.link(obnew)
Thanks for the suggestion. The Stop-motion code is somewhat similar to what I want to do. Unfortunately the code doesn’t deal with removing objects. It seems to load all stl frames into memory. I can easily to the same with my current method but would run out of memory.
You might be getting in trouble due to removing an object from bpy.data.objects while also iterating over the same list. Try doing it in two phases: 1) go through bpy.data.objects to make a separate list R of objects to remove, 2) iterate over R and delete each of the objects.
I encountered the same crashes with your code, but I realized that the crashes only occured during renders, whereas the code worked flawlessly when playing the animation in the timeline. There seems to be a threading problem in Blender when previewing the scene while rendering, so activating “Lock Object Modes” and rendering internally instead of opening a separate window (in the preferences) solved the issue for me. I furthermore edited your code to keep the selection when switchign frames (as otherwise the import gets selected deselecting previous selections):
import bpy
import os
## Get Directory
head,tail=os.path.split(bpy.data.filepath)
bpy.context.scene['datadir']=os.path.join(head,"Frame_STL")
bpy.context.scene['prevframe']=0
print('------------------------------------------------------------------')
## Define the object exchange script
def doatnewframe(scene):
obj_name2='Tesst Frame ' #Objects are named with capital letters at the beginning of words and without underscores
obj_name='test_frame_'
max_frame=124 #Last frame that gets an exchanged model
tot_ang=math.pi
last_frame=bpy.context.scene['prevframe']
curr_time=bpy.context.scene.frame_current
timedir=min(curr_time,max_frame)
timedir=max(1,timedir)
bpy.context.scene['prevframe']=timedir
if timedir!=last_frame:
#Selected objects
prev_sel=bpy.context.selected_objects
prev_selected=[]
for ps in prev_sel:
prev_selected.append(ps.name)
found_list=-1
for i in range(0,len(prev_selected)):
s=prev_selected[i]
if obj_name2 in s:
found_list=i
add_new=0
if found_list>=0:
prev_selected.pop(found_list)
add_new=1
# delete old object created at previous frame
for o in bpy.data.objects[::]:
if obj_name2 in o.name:
o.parent=None
bpy.data.objects.remove(o,do_unlink=True,do_ui_user=True)
for m in bpy.data.meshes[::]:
if obj_name2 in m.name:
bpy.data.meshes.remove(m,do_unlink=True,do_ui_user=True)
# import new object from stl for current frame
stlfilename=os.path.join(bpy.context.scene['datadir'],obj_name+str(timedir)+'.stl')
bpy.ops.import_mesh.stl(filepath=stlfilename)
# get object with newly loaded stl
new_ob_name=obj_name2+str(timedir)
ob_new=bpy.data.objects[new_ob_name]
ob_new.location=(0,0,2.6)
if timedir<max_frame:
z_rot=tot_ang*(1-math.cos(math.pi/2*timedir/max_frame)**2)
scaler=0.2+0.8*math.sin(math.pi/2*timedir/max_frame)
else:
z_rot=tot_ang
scaler=1
ob_new.rotation_euler=(0,0,z_rot)
ob_new.scale=(0.25*scaler,0.25*scaler,0.25*scaler)
# link newly loaded object to scene
bpy.context.scene.collection.objects.link(ob_new)
# Add Material to new object
# Get material
mat=bpy.data.materials.get("Silver")
# Assign it to object
if ob_new.data.materials:
# assign to 1st material slot
ob_new.data.materials[0] = mat
else:
# no slots
ob_new.data.materials.append(mat)
for poly in ob_new.data.polygons:
poly.use_smooth = True
# Select object
for p in prev_selected:
bpy.data.objects[p].select_set(True)
if add_new==1:
bpy.data.objects[new_ob_name].select_set(True)
else:
bpy.data.objects[new_ob_name].select_set(False)
print("Changed Objects for Frame:0 ", curr_time)
bpy.app.handlers.frame_change_pre.clear()
bpy.app.handlers.frame_change_pre.append(doatnewframe)
doatnewframe(bpy)
Hi Ntropic,
I change the settings from Render in “New Window” to Render in “Keep User Interface”. Lock Object Modes was already enabled. I still got the crash.
Your idea sparked an idea to try run it without GUI. I tried this idea on the bug report I made back in december, https://developer.blender.org/T72691.
blender -b A.blend --python-text stlbyframe.py -a > A.log
The result was a succes because blender did not crash.
@jdk@Josephbburg
I’m working on the next version of the Stop Motion OBJ addon, which is just about to enter beta testing. I’ve added a feature called Streaming sequences that imports meshes during the animation. There’s also a mesh cache and the add-on will automatically remove meshes once the cache fills up. If you still need this kind of functionality, I think it’d be worth a try for you.