Writing to a text object in a driver behaviour 2.60.0,1,2,3

Hello,

In some driver methods I’ve used


import bpy
def frame(n):
    if "Text" in bpy.data.objects:
        textobj = bpy.data.objects["Text"]
        textobj.data.body = 'Frame:%d'%n
        print(textobj.data.body)
    return(0.0)

bpy.app.driver_namespace["frame"] = frame

Wire it up in a driver and pass the Scene > current_frame to it as a variable.

This worked fine in 2.60.0 changed the body of the text in UI and render.
In 2.60.2 no change in UI (unless edit mode is toggled like selecting verts) or in render where edit mode toggle isn’t an option
In 2.60.3 changes in render but not in UI.

Anyone else experiencing this?

could be,
i did not test this with different versions.

I always use the frame_change_pre handlers call.
But the reason i do it, is i noticed those problems
when things did not update with a driver.
There is another thing with a driver,
if the object with the driver has some depenencies
to other objects it could happen it is triggered again and
again and its wasting a lot of cpu-power.

This is the reason why i use a seperate empty-object
with no use as parent to other objects or one of those
might trigger the driver-evaluation again, when its animated.

First check, if those working combinations are not one of those
with an driver running in an endlos loop and eat up the cpu-power.

There are other problems too, those animation-updates are a bit to late
for the render process and its not possible to trigger a scene-update
in those parts - because this would again run the driver … and this triggers the update again … and so on – its a deadly (crash-proven) looping.

(should i append a small blend-file with display of this animation-problem?)

Asked CB about it and got sent to the bug tracker. Here is a simple sample.

I’m using r41779 and it renders ok but doesn’t show in the UI / OpenGL render.

PS the print in the driver gives a pretty good indication that its not looping etc etc.

Attachments

textobj.blend (75.9 KB)

Confirmed, the developers broke it again.

But this modification did work on r41810. Add a scene update.


import bpy
def frame(n):
    if "Text" in bpy.data.objects:
        textobj = bpy.data.objects["Text"]
        textobj.data.body = "Frame:" + str(n)
        print(textobj.data.body)
    bpy.data.scenes[0].update()
    return(0.0)

bpy.app.driver_namespace["frame"] = frame

Thanks Atom.
Unless it gets “fixed” had to go for this


import bpy
def frame(n):
    if "Text" in bpy.data.objects:
        textobj = bpy.data.objects["Text"]
        if "frame" not in textobj:
            textobj["frame"] = -9999
        if textobj["frame"] != n:
            
            textobj.data.body = 'Frame:%d'%n
            print(textobj.data.body)
            textobj["frame"] = n
            bpy.data.scenes[0].update()
        
    return(0.0)

bpy.app.driver_namespace["frame"] = frame

Just having a scene update in there made it roll over until the recursion limit was reached.

I am looking at this thread and wondering what the code does. It does not seem to update the Text object. However, there is no error message.

Is the code actually incomplete?

I changed the code like below, using handler thing, kind of work, however, code seems to be getting called all the time (waste of resources) I am getting an error message in the background: “maximum recursion depth exceeded”.

Can that be fixed? Or maybe I just want to update every frame changes, not all the time.

Thank you.

Code is below:

import bpy

def frame(n):
    
    cur_frame = bpy.context.scene.frame_current
    
    if "Text" in bpy.data.objects:
        textobj = bpy.data.objects["Text"]
        textobj.data.body = "Frame: " + str(cur_frame)
        #print(textobj.data.body)


    bpy.data.scenes[0].update()


    return(0.0)


#bpy.app.driver_namespace["frame"] = frame


bpy.app.handlers.scene_update_pre.append(frame)

Am I doing the right thing:

import bpy

def frame(n):
    
    cur_frame = bpy.context.scene.frame_current
    
    if "Text" in bpy.data.objects:
        textobj = bpy.data.objects["Text"]
        textobj.data.body = "Frame: " + str(cur_frame)
        #print(textobj.data.body)


    bpy.data.scenes[0].update()


    return(0.0)


#bpy.app.driver_namespace["frame"] = frame


bpy.app.handlers.frame_change_post.append(frame)

You are kind of mixing drivers and handlers and that wont work. As a driver you must return a float value, however a frame change does not. Also a handler receives a scene which you are not making use of. Remember, the context will be None when you render so you can not rely on that to fetch current_frame when rendering.

Here is how I would set it up as a handler.


import bpy

def frame(scene):
    cur_frame = scene.frame_current
    
    if "Text" in bpy.data.objects:
        textobj = bpy.data.objects["Text"]
        textobj.data.body = "Frame: " + str(cur_frame)
        #print(textobj.data.body)

bpy.app.handlers.frame_change_pre.append(frame)

Here is how I would set it up as a driver.


import bpy

def frame(n):
    # Create a scene variable in the driver and pass the frame number.
    cur_frame = n
    if "Text" in bpy.data.objects:
        textobj = bpy.data.objects["Text"]
        textobj.data.body = "Frame: " + str(cur_frame)
        #print(textobj.data.body)

    return(0.0)

bpy.app.driver_namespace["frame"] = frame

@ATOM
You clear everything up! Thank you so much!