Handler Event Order (swapping proxy for mesh at render)

Hi All,

In a recent script I noticed that events in my console display were not appearing in the order that I thought they should. This lead me to create a small test script to verify event handlers do indeed operate in the correct order.(they seems to)

What I noticed is that frame_change_pre and frame_change_post seem to be the same thing. For instance, what is frame_change_post to? I assumed frame_change_post was post to scene update but I am not sure? And what happens if I issue a mesh.update() inside a frame_change_pre? Also scene_update seems to run constantly if you uncomment those two lines. Is that normal?

So here is my example script that detects the render process, swaps the default cube for a triangle before rendering begins. The triangle is rendered instead of the cube. After render is complete another handler swaps the default cube back into the data slot of the object.


import bpy, time
from mathutils import Vector

global isRendering, mesh_name

def fetchIfMesh(passedName=""):
    try:
        result = bpy.data.meshes[passedName]
    except:
        result = None
    return result

def returnSingleTriangleMesh(passedName):
    me = fetchIfMesh (passedName)
    if me == None:
        vp_points = []
        vp_faces = []
        vp_objects = []
        vp_D1 = Vector([0.06, 0.08, 0.0])
        vp_D2 = Vector([0.06, -0.08, 0.0])
        vp_D3 = Vector([-0.1, 0.0, 0.0])
        vp_scale = 6.0
        c = 0
    
        # Single triangle object at world origin.
        dd = Vector([0.0,0.0,0.0])
        vp_points.append(dd+vp_D1*vp_scale)
        vp_points.append(dd+vp_D2*vp_scale)
        vp_points.append(dd+vp_D3*vp_scale)
        vp_faces.append([c,c+1,c+2])        
    
        me = bpy.data.meshes.new(passedName)
        me.from_pydata(vp_points,[],vp_faces)
    else:
        # Just use the existing mesh.
        pass
    
    # Make sure all verts are deselected.
    for v in me.vertices:
        v.select = False
    me.update()
    return me

def render_pre(passedScene):
    global isRendering
    isRendering = True
    print ("
EVENT: render_pre")
def render_post(passedScene):
    global isRendering,mesh_name

    # Restore the cube.
    ob = bpy.data.objects["Cube"]
    me_old = ob.data
    print ("recovering mesh [" + mesh_name +"].")
    me_new = bpy.data.meshes[mesh_name]
    print ("assigning mesh [" + me_new.name +"] to the viewport.")
    ob.data = me_new
    print ("removing mesh [" + me_old.name +"].")
    bpy.data.meshes.remove(me_old)
    isRendering = False
    print ("EVENT: render_post
")
def render_stats(passedScene):
    print ("EVENT: render_stats")


def frame_change_pre(passedScene):
    global isRendering,mesh_name
    
    if isRendering == True:
        #Remove the cube.
        ob = bpy.data.objects["Cube"]
        me_old = ob.data
        mesh_name = me_old.name
        print("saving name [" + mesh_name + "].")
        
        #Render a triangle
        me_new = returnSingleTriangleMesh("me_triangle")
        print ("assigning mesh [" + me_new.name +"] to be rendered.")
        ob.data = me_new
    else:
        # GUI frame change.
        pass
    
    print ("EVENT: frame_change_pre")
def frame_change_post(passedScene):
    print ("EVENT: frame_change_post")
        
def scene_update_pre(passedScene):
    print ("EVENT: scene_update_pre")
def scene_update_post(passedScene):
    print ("EVENT: scene_update_post")

def load_pre(passedScene):
    print ("EVENT: load_pre")
def load_post(passedScene):
    print ("EVENT: load_post")
def save_pre(passedScene):
    print ("EVENT: save_pre")
def save_post(passedScene):
    print ("EVENT: save_post")
    
# Setup our event handlers.
bpy.app.handlers.render_pre.append(render_pre)
bpy.app.handlers.render_post.append(render_post)   
bpy.app.handlers.render_stats.append(render_stats)                   
bpy.app.handlers.frame_change_pre.append(frame_change_pre)
bpy.app.handlers.frame_change_post.append(frame_change_post)

bpy.app.handlers.load_pre.append(load_pre)
bpy.app.handlers.load_post.append(load_post)                      
bpy.app.handlers.save_pre.append(save_pre)
bpy.app.handlers.save_post.append(save_post)

#bpy.app.handlers.scene_update_post.append(scene_update_post)                      
#bpy.app.handlers.scene_update_pre.append(scene_update_pre)

The net result is that this script renders one mesh as if it were another mesh.


Attachments

26_handler_event_order.blend (390 KB)

Thanks! This answers quite a few questions!