How to Determine what sub-frames Python code will see

   3335   8   2
User Avatar
Member
2044 posts
Joined: Sept. 2015
Offline
Hi,

As the topic asks I am having problems in my code being able to pick a specific point in time or frame when using hou.time() or frame.time()

My code works fine if the Global Animations Options has Integar frame values ticked on.

However if I take it off, my python code never sees the specific interval so the code doesn't get executed.

If in my Python Source Editor I have a variable say “The_x” set to 0.0 and then in my python node I doing something like:

if hou.frame() == 30:
hou.session.The_x = 5.0

or

if hou.time() == 6:
hou.session.The_x = 19.0

in either case with the check box set for Integer frame values both sets of code give what I expect.

With it checked off, its as if it never saw those values; 30 with hou.frames() or 6 with hou.time()

Should this code be “seen” in either case or is there some inherent limit with the option being checked off ( Integer frame values ) ?

Thanks for any feedback.
User Avatar
Member
818 posts
Joined: Sept. 2013
Offline
In non-integer frames, if you run the code:
print hou.frame()
You'll see that it prints out decimal values, like 1.2345, and 1.2345 doesn't equal to 1. You probably want to use math.floor() [docs.python.org] to round down the returned value:
import math
print math.floor(hou.frame())
You can then compare the result with an integer number.

If you don't care about negative frames, it's slightly shorter to do:
print int(hou.frame())

There's also round() [docs.python.org] that you could use to get the closest integer, instead of rounding down.
Andrew / アンドリュー
User Avatar
Member
2044 posts
Joined: Sept. 2015
Offline
Hi awong,

Thank you for that reply.

I changed my code and it now works but I had simplified my original question, and maybe I shouldn't have but hopefully you catch this reply and may be able to offer more insight.

So I originally changed my code from:

if (hou.frame()) == 120:

to

if (hou.frame() > 120.0) and (hou.frame() < 120.1):

and this worked because like you demonstrated with the print and floor function we are only getting values like 120.023.

So am I to understand that when we use this non-integer setting to get subframes that the sequence of subframes is “undetermined”?

Like in my case using 120 as my aim.

Does the sequence possibly go like:

119.897, 119.976, 120.063, 120.341, etc.

hence the reason it never “sees” 120.000 is because it was never created?

So in my case in the screenshot of my code I am using a sin function to drive changes in an object and using the subframe values to make changes.

So I have a range of < 120 where I do something, then at and only at 120 intend to make a specific change then carry on with something different with values only > 120.

So both with my alternative as I said above and your suggestion of using floor my code works.

But perhaps in this case I don't see the possible difference in results. And what I mean is that what I want to happen at say 120 is likely really happening at another subframe like say 120.024.

I am probably splitting hairs too much and in my particular case I am not seeing any difference but wonder if at another point in time when say I want something to happen at “exactly” “120” I might see a difference.

So again, I was hoping I could get some more insight as to what is going on.

I've read subframes are calculated to 3 decimal points.

But does this mean they run through sequentialy for each value?:

119.998, 119.999, 120.000, 120.001, 120.002, etc.

and for each value the code in a python node is looked at?

This is what I originaly thought which is why I was a little perplexed when it seemd like the “ == 120” wasn't being “looked” at.

I hope I am clear enough and appreciate if you could offer your thoughts on this.

Thank you

Attachments:
Sub-Frame-with-Python.jpg (129.6 KB)

User Avatar
Member
818 posts
Joined: Sept. 2013
Offline
What do you mean by “sequence”? If you're simply stepping through the frames (e.g. left/right arrow key, or clicking -/+), the default behavior is to add/minus 1 to the current frame number. For example, if the current frame is 1.2, then the next step will be at 2.2, 3.2, 4.2, etc. This default step can be changed in the “Global Animation Options” dialog. you could change it to 0.5, 0.1, or anything you want.

But if you're just clicking/scrubbing the frames from the play bar, then the subframe that you get is completely depended on where you click in the play bar. Since there are infinite real numbers between two integers, you could get 3.4, or 3.45, or 3.345, etc. There isn't really a “sequence” of subframes.
Andrew / アンドリュー
User Avatar
Member
2044 posts
Joined: Sept. 2015
Offline
Hi,

Ok, so what I mean by sequence is when I reset the pay bar to the start and just press play and let it run.

In this case sequence meaning how are the frames getting incremented and by what value.

So what I am assuming is that for each frame or subframe value the python code in the node is “called”.

So for example if I have subframes turned off I am assuming that the sequence of frames being played will be sequentially:

1,2,3,4…etc. or rather frame1, frame2, frame3, frame4, etc.

Again, I am assuming for each frame number the program looks at the current frame number and with that value looks through the python code in the node to see what will be executed.

So say I have code that says ‘if hou.frame() == 3: then do this’…

well, again I am assuming that this code is looked at for each frame value ‘as it occurs’…sequentially….

when the frame is at 1 or 2 or 4 or 5 and so on nothing will happen because the condition hasn't been met…

but something should happen at frame 3.

But if I turn on sub-frames nothing will happen at frame 3. But it will happen at 3 if sub-frames is turned off.

I understand with sub-frames on we can get values of 2.856 or 3.023; or do we?

How can I ever get something to happen at 3.000 and only at 3.000? (with subframes on)

With math.floor(hou.frames()) it leads me to believe that I may be using another value other than 3…

because it might be taking say subframe 3.234 and converting it to 3 just to be able to do the code.

Am I to understand that by doing something like math.floor(hou.frames()) that the resulting value,

in this case 3 is the actual “driver” of the frames rather than the other way around?

Meaning the code determines what frame values get created and not that the frame values determine what code gets executed?

I had already looked at Global Animation Options for the default step option and played with that;

And yes it will step your frames when you use the ‘+’ and ‘-’ buttons.

But if you run the keyframes with ‘play’ button it doesn't run to that setting

eg. if you have it set to 50, it doesn't play every 50 frames it still runs through each number 1-50 and every sub-frame of each number, although what the subframes are is difficult to determine because they go so fast.

Hope this is more clear in helping me understand how the code gets run in relationship to how the frames are run.

Thank you
User Avatar
Member
818 posts
Joined: Sept. 2013
Offline
Do you also have “Realtime Playback” turned on? That would cause the “play” button to go into subframes, depending on the playbackspeed. Otherwise, the “play” button should also follow the “step” value.

If you indeed want to handle the “Realtime Playback”, then your Python code logic would have to be more complicated. In a heavy scene, the playback could jump from frame 2 to frame 10 directly, skipping a lot of frames between. So your Python code would have to handle these cases.
Andrew / アンドリュー
User Avatar
Member
2044 posts
Joined: Sept. 2015
Offline
Hi awong,

I really appreciate you taking the time to answer my questions.

Yes I was running Realtime Playback, and as you say goes into subframes.

You also said if its a heavy scene it could jump frames?

So this is why in my case it “missed” my statement to do something like “ if hou.frame() == 120: do something” that perhaps it was a “little busy” at that point and skipped a bit?

The only reason I had it set for Realtime Playback is so I could get a general check on what the final motion will be like.

So what seems to be the solution is when I want to check my code at specific places like in my case I wanted something to happen at frame 120…perhaps just go out of realtime playback set the step value to 3 decimal places ( same as subframes ) and just step through and observe if what happens is what I want kind of thing?

And then maybe for overall flow of the work I can go to realtime playback?

Thanks again.
User Avatar
Member
818 posts
Joined: Sept. 2013
Offline
Maybe it's good to reconsider what kind of result you're trying to achieve. Judging from your code snippet, maybe using Python SOP is not the best way to do what you want.

if you want some sort of oscillating motion, it's possible to achieve something similar with a single expression set onto the rz parameter directly. For example, something like:
sin($F)*90

If you want slightly more complex motions, you could look into using CHOP, which lets you use CHOP nodes to create pattern that could be used to drive the rz parameter.

Those would save you some headache from needing to figure out how to handle these skipping frame cases.
Andrew / アンドリュー
User Avatar
Member
2044 posts
Joined: Sept. 2015
Offline
Hi awong,

Thanks again,

Yeah because not only do I want the oscillating motion but the ability to change direction anywhere along its motion and expand or contract its range of motion with slider controls.

Although I haven't yet studied how to use chops, I was aware of them and did view to some degreee a couple ‘tutorial’ videos on them, although I didn't see a way to accomplish what I wanted with them.

That's not to say I can't; I did see the potential in using them.

I'm glad you mentioned Chops to me.

I think I will revisit them and study them a bit more closer.

Thank you very much, you've helped me along here towards learning how to get more out of Houdini - much appreciated.
  • Quick Links