Python LOP reading attributes incorrectly

   3785   7   1
User Avatar
Member
207 posts
Joined: Nov. 2015
Offline
Hi;

I have a Python LOP, which I'd like to use to read some data from a prim in my USD Scene Graph, do some math, and set some other attributes on the same prim. In my case, the prim in my main camera.

I'm setting Focal Length on my camera:


Easy enough. And I can verify it's there in my Scene Graph Details:



However, in Python, I'm doing this:
node = hou.pwd()
stage = node.editableStage()
camera = stage.GetPrimAtPath('/world/cameras/render_cam')
focal_length_attr = camera.GetAttribute('focalLength')
focal_length = focal_length_attr.Get()
print(focal_length)

The output is "50.0". I'm quite confused...what am I doing wrong?

Thanks!

Attachments:
camera_1.png (45.5 KB)
camera.png (90.5 KB)

User Avatar
Member
354 posts
Joined: Nov. 2013
Offline
Using Get() with no arguments will return the default value for the attribute, which appears to be 50. The green text in the scenegraph details pane indicates that the focal length attribute has time samples. To get at those values you’ll need to pass a TimeCode to Get() I guess constructed from hou.frame() (I’m not at a computer to check that works right now so apologies if that’s wrong).

If you weren’t expecting there to be time samples on the attribute you might want to check where they are coming from as its not uncommon for nodes to create animated data unnecessarily
Edited by antc - June 6, 2022 01:13:51
User Avatar
Staff
4565 posts
Joined: July 2005
Offline
You aren't passing a time value to focal_length_attr.Get(). You should _always_ pass a time value to Usd.Attribute.Get() (even though technically the argument is optional). The default behavior if you don't specify a time is Usd.TimeCode.Default, which will retrieve the "default" value of the attribute, regardless of any time samples set on the attribute. In your case, you have the focalLength set as a time sample (you can tell by the green color in the scene graph details). So when you query the "default" value, you get the fallback value from the UsdGeomCamera schema definition.

If you actually don't care about the time (you know the value isn't changing with time), use Usd.TimeCode.EarliestTime. This will return the "default" value if there are no time samples set, or the first time sample if there are time samples set. If there is any change that there will be a time-varying value, you should use Usd.TimeCode(hou.frame()), which will return the time sample closest to "now", or the "default" value if there are no time samples. The problem with this expression is that it will introduce a time dependency if the expression is in a node's parameter (because of the use of hou.frame()). So if you want to be really safe, you might want to check if the attribute has any time samples. Use Usd.TimeCode(hou.frame()) if it has more than one time sample, or use Usd.TimeCode.EarliestTime if the attribute has zero or one time samples.

We're looking at putting this bit of attribute fetching logic into a utility python method for the next release of Houdini for convenience, but it's only four or five lines of code.

Edit: @antc beat me to it
Edited by mtucker - June 6, 2022 01:16:29
User Avatar
Member
207 posts
Joined: Nov. 2015
Offline
Oh this is interesting, thank you! I wouldn’t have considered this, as I’m not considering my scene to be animated. When I bring geo in from SOPs using sopImports, I’m trying to be conscious of not authoring any time samples, but I hadn’t considered expressions on LOP nodes. I’m setting my focal length with a standard (fit(rand)) expression; is there a way for me to somehow tell houdini not to author time samples for this? Or is focalLength going to always be considered animated by virtue of using an expression at all?
User Avatar
Member
354 posts
Joined: Nov. 2013
Offline
dhemberg
I’m setting my focal length with a standard (fit(rand)) expression; is there a way for me to somehow tell houdini not to author time samples for this? Or is focalLength going to always be considered animated by virtue of using an expression at all?

Are you using $F or $T in the expression perhaps? For me (in 18.5) Houdini seems to do the right thing and author a default value when the expression isn't time dependent.
User Avatar
Staff
4565 posts
Joined: July 2005
Offline
You'd need to provide a hip file for more in-depth answers on the time dependency question.
User Avatar
Member
207 posts
Joined: Nov. 2015
Offline
Ok great; in trying to winnow down my scene to prepare to share it, I noticed that at one point I disconnected the node feeding into my camera (to try to isolate the camera). The Python snippet suddenly started working. So, I started tracing my way back up my stage, and found a SOP network containing a LOP Import node, which has a default Import Frame value of $FRAME, which triggered an animated dependency down the rest of my LOP network.

Removing that single expression (which I clearly hadn't even paid attention to) caused my Python node to properly read my 'default' focal length (which itself has no dependency on time...I'm doing rand(@seed), where @seed is a Context Option I set).

I'm grateful both to have a raised awareness of time dependencies in my LOP graph, and to know better hygiene for the Get() method with USD prims. So, thank you!
User Avatar
Member
354 posts
Joined: Nov. 2013
Offline
Hmm yeah it looks like if a camera has an input with a time dependency, all the attributes with authored values become time sampled. That's a little unfortunate but I guess a separate branch holding all the time uniform nodes would work. Kind of tricky though when nodes become time varying in the future (which is bound to happen somewhere) as it would require moving those nodes out of the time-uniform branch.
Edited by antc - June 6, 2022 14:11:43
  • Quick Links