Python and getting prim attributes

   5910   7   2
User Avatar
Member
10 posts
Joined: July 2018
Offline
Hello. I know there have been a few different questions similar to the one I'm about to ask, but I think I've just looked at so much usd/python code at this point I just need someone to explain it to me.

Here is some test code I'm using to try and understand whats going on:

import hou
from pxr import UsdGeom

node = hou.node('/stage/redshift_rendervars/HDRI_Diff') ## this node exists

stage=node.stage()
nodePath = hou.LopNode.path(node) ## getting Lop node selected but I think this is pointless?
prim = stage.GetPrimAtPath(nodePath) ## thinking I need the path of the Lopnode to actually get the prim

print (prim)

This returns "invalid null prim)


Now I assume part of the problem is I'm combining the use of hou.node and USD, or something. Maybe USD doesn't update based on the existence of nodes in the heirarchy? But it is plugged in, the scene graph sees it, it's all there. I tried force cooking it as well, that didn't do anything.

In the long run what I'm trying to do is create light select rendervars based on the upstream created lights. I have the rendervars creating, naming, and assigning the sourceName appropriately so they can be diff and spec etc. But I've gotten hung up on the LightGroup part, where I change the 'driver:paramaters:aov:RS_LightGroup' (that might be typo'd) to be "Set or Create", but for the life of me I can't figure out how to actually access that attribute and change it.

Any help is greatly appreciated, no matter how small!
User Avatar
Member
240 posts
Joined: Oct. 2014
Offline
GetPrimAtPath() expects a USD stage path rather than a node path. So for example if you create a sphere and set its scenegraph location to "/someAsset/sphere", you would do GetPrimAtPath("/someAsset/sphere")

In your example, your renderVar LOP node is generating a RenderVar primitive on the USD stage, visible in the scenegraph. It's this primitive's path that you need to pass to GetPrimAtPath().
Edited by Tim Crowson - Sept. 21, 2022 21:32:43
- Tim Crowson
Technical/CG Supervisor
User Avatar
Member
10 posts
Joined: July 2018
Offline
Hi Tim!

That makes seeeeense. I knew there a gap in my logic. Ok I'll give that a whirl tomorrow! Thanks!
User Avatar
Member
176 posts
Joined: Nov. 2013
Offline
Here's what I've got, although the last line causes an error.
line 23, in <module>
AttributeError: 'str' object has no attribute 'Set'
Anyone want to chime in with why my terrible code won't let me Set the Attribute value?

import hou
from pxr import UsdGeom, Sdf, Usd

stageloc  = hou.node("/stage") #Get /stage Lop path location
rendervar_name = "HDRI_Diff"
rendervarlop = stageloc.createNode('rendervar', rendervar_name) #create a rendervar lop in /stage context
myprimpath = '/Render/Products/RS_vars/' + str(rendervar_name) #Create a variable for the Scene Graph Tree location aka stage location aka primpath
rendervarlop.parm('primpath').set(myprimpath) #Set the primpath to the above variable
#Changing a parm on a node like 'Set or Create' requires the lop node location, like on line 4
rendervarlop.parm('xn__driverparametersaovchannel_prefix_control_u7bkd').set('set') #Set the weirdly named control parm

#Getting Scene Graph Tree PrimPaths
stage = rendervarlop.stage()
prim = stage.GetPrimAtPath(myprimpath)
print (prim)

#Changing a primvar or attribute 'driver:parameters:aov:name' like requires the primpath aka Scene Graph Tree location aka stage location
channelprefixattr = prim.GetAttribute('driver:parameters:aov:channel_prefix').Get()
channelprefixattr.Set('blah')
Edited by Hamilton Meathouse - Sept. 24, 2022 20:05:44
User Avatar
Member
277 posts
Joined: Nov. 2013
Online
You instead want this so you are getting the UsdAttribute object, not the string value the attribute is holding (via Get())
Then you can call Set on the UsdAttribute (channeprefixattr). Your code was trying to call Set() on the string value.
channelprefixattr = prim.GetAttribute('driver:parameters:aov:channel_prefix')
channelprefixattr.Set('blah')
Edited by antc - Sept. 25, 2022 00:34:42
User Avatar
Member
176 posts
Joined: Nov. 2013
Offline
Thanks Antc. Sadly that throws a different error:
Traceback (most recent call last):
File "dan_code", line 22, in <module>
pxr.Tf.ErrorException:
Error in 'pxrInternal_v0_22__pxrReserved__::SdfLayer::SetField' at line 3631 in file C:\cygwin\home\prisms\builder-new\WeeklyDevToolsHEAD\dev_tools\src\usd\usd-22.05\USD-py3.9\pxr\usd\sdf\layer.cpp : 'Cannot set default on </Render/Products/RS_vars/HDRI_Diff.driver:parameters:aov:channel_prefix>. Layer @anon:0000000060A5E200:LOP@ is not editable.'
User Avatar
Member
277 posts
Joined: Nov. 2013
Online
Maybe try rendervarlop.editableStage() instead of rendervarlop.stage(). I think the later only gives you a read-only stage (the lops output).
User Avatar
Staff
453 posts
Joined: June 2020
Offline
Sorry to join this thread a bit late, but I want to rewind a bit and make sure I understand what's required here. What I'm reading just above about trying to write to the USD Stage of a "random" node has me a bit concerned.

If I've got it right, you're trying to programmatically create rendervar nodes and maybe(?) pre-populate some of the data based on what's currently in the stage?

For the first part (creating the rendervar nodes), it seems like you're already in good shape.

Regarding "weirdly named", you can pass hou.text.encode('driver:parameters:aov:channel_prefix_control')rather than 'xn__driverparametersaovchannel_prefix_control_u7bkd'.

So now you want to set the driver:parameters:aov:channel_prefixdata. You shouldn't be trying to set this directly on the stage's USD Attribute but, rather, on the Houdini node's Parameter.

parm = rendervarlop.parm(hou.text.encode('driver:parameters:aov:channel_prefix'))
parm.set(THE_DEFAULT_VALUE_YOU_WANT)

If THE_DEFAULT_VALUE_YOU_WANTis coming from the USD Stage that feeds into the rendervar node, then you can (as per the earlier suggestions) use somenode.stage().GetPrimAtPath(...).GetAttribute(...).Get()to get the value. Note, however, somenodehere should be a node that feeds into the rendervar node, not the rendervar node itself, as I expect you want to get the value *before* the rendervar node updates it.

Hopefully I've roughly understood your goal and am not steering you down the wrong path
Edited by robp_sidefx - Oct. 3, 2022 10:17:58
  • Quick Links