1
$\begingroup$

I tried to use frame_change_pre to animate my scene in a fully python generated way ( No keyFrame ). The scene worked fine in viewport but stood still in render.

So I went for the onion strategy : I striped my file of the most complicated objects and python function. The result is the following minimal file ... that still has the same problem. Here is the Python code :

def frame_handler(scene, depsgraph):
    
    frame = scene.frame_current
    M = scene.objects["M"]
    current_world = scene.world
    x = current_world["x"] 
    M.location = (x,x,x)
    print(str(x))  


                                
#    Event Listener   Frame Change
bpy.app.handlers.frame_change_pre.clear()
bpy.app.handlers.frame_change_pre.append(frame_handler)

Edit : As I said in the comments, the problem comes from x = current_world["x"] Accessing this custom variable during render is the problem. If I change it with x = frame/30 ... I get the motion ...

Any idea to solve this would be welcome and would let me add back a few onion layers ... T H A N K S.

Here is the file :

$\endgroup$
4
  • $\begingroup$ Does it work if you also append your handler to bpy.app.handlers.render_pre or bpy.app.handlers.animation_playback_pre? $\endgroup$
    – Jakemoyo
    Commented Jul 31 at 19:30
  • $\begingroup$ Hi Jakemono, Same problem with both ... $\endgroup$
    – Nicolas
    Commented Aug 1 at 7:51
  • $\begingroup$ When I replace x = current_world["x"] by another way to change x like x = frame/30 ... it works. So the problem is to access this custom property ... during render ... $\endgroup$
    – Nicolas
    Commented Aug 1 at 7:53
  • $\begingroup$ This is not yet a correct "minimal working example", because I get errors related to file paths which obviously aren't present on my machine. Please create a new project, and reproduce the problem there using as few steps as possible. How to upload a blend file on BSE - good practices and advice $\endgroup$ Commented Aug 1 at 8:22

2 Answers 2

3
$\begingroup$

You need to evaluate the frame first before you can access the evaluated data, which you do by using the frame_change_post event and accessing the depsgraph argument:

import bpy
import math
import numpy as np 


def frame_handler(scene, depsgraph):
    
    frame = scene.frame_current

    M = scene.objects["M"]
    current_world = scene.world.evaluated_get(depsgraph)  # HERE
    x = current_world["x"] 
    M.location = (x,x,x)
    print(str(x))  


                                
#    Event Listener   Frame Change
bpy.app.handlers.frame_change_pre.clear()  # just once
bpy.app.handlers.frame_change_post.clear()
bpy.app.handlers.frame_change_post.append(frame_handler)

If you really want to do this in frame_change_pre then you could have both _pre and _post and in the _post store the last evaluated value (which will be 1 frame behind when accessed by _pre) or otherwise you can evaluate the fcurve associated with the property to get the data for current frame number... Of course this solution is not generalized and it works when the property is animated by an f-curve, not when the relation is more complex and requires evaluating the depsgraph.

$\endgroup$
6
  • $\begingroup$ Thanks Markus ! ( Your answer is clear, usable, and used : it works ). Though as I said in the original file, I experience a systematic crash, probably du to the use of context as in bpy.context.collection.objects.link(object). I am not sure how to replace this lines using depsgraph instead ... $\endgroup$
    – Nicolas
    Commented Aug 1 at 10:09
  • $\begingroup$ "Though as I said in the original file, I experience a systematic crash" - I only see a "crash" mentioned in your answer where you mention disabling "Lock interface", which is supposed to help with the crashes, but ultimately the problem you run into is that you're changing the scene after it has already been prepared for rendering. So maybe you do want to use frame_change_pre but evaluate the objects of interest using your own depsgraph (dg = bpy.context.evaluated_depsgraph_get()). For an onion effect you might want to play the animation once, gather data, and then render? $\endgroup$ Commented Aug 1 at 10:30
  • $\begingroup$ As I said, the example provided here is not the original file I was working on, and is simplified for the sake of clarity. ( I clumsily called the simplification "onion striping ). In the original file, I indeed delete and recreate every objects, depending on the animated value of x = current_world["x"] . So now, I will correct my file using your dg = bpy.context.evaluated_depsgraph_get() If it doesn't work I may start another post as the problem is significantly different from this post's . ( What do you think ? ... I create a new post ? ) T.H.A.N.K.S $\endgroup$
    – Nicolas
    Commented Aug 1 at 10:49
  • $\begingroup$ @Nicolas go for it, perhaps concentrate on the effect you want to achieve, to avoid en.wikipedia.org/wiki/XY_problem ? Though remember the question should be simple rather than asking for some complex tutorial on achieving some elaborate effect... $\endgroup$ Commented Aug 1 at 13:35
  • $\begingroup$ New post : blender.stackexchange.com/questions/322360/… $\endgroup$
    – Nicolas
    Commented Aug 1 at 15:01
0
$\begingroup$

I unchecked the "Lock interface" option in Render menu. The problem seems to be solved, as if the Interface was needed to read customs properties. ... but I have now to deal with the numerous crashes my scene generates when the "Lock interface" option is unchecked .

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .