LopSelectionRule - I'm doing it wrong

   4434   16   4
User Avatar
Member
31 posts
Joined: June 2016
Offline
Hi
I'm trying to resolve a LopSelectionRule and yet in the simplest of scenes I get an error saying “infinite recursion” - what am I doing wrong here?

Attachments:
Screenshot 2020-11-11 173840.png (238.8 KB)

User Avatar
Member
7771 posts
Joined: Sept. 2011
Offline
instead of hou.pwd(), what about the input node?

Edit:
I get a warning about a read lock fail due to existing lock when I tried it. Not sure how it's supposed to be used.
Edited by jsmack - Nov. 11, 2020 20:49:48
User Avatar
Staff
4438 posts
Joined: July 2005
Online
From the drop down next to the python code parameter, choose “Dim All Lights”. It shows how to use a LopSelectionRule in a python LOP, and explains why things need to be done in a particular order.
User Avatar
Member
31 posts
Joined: June 2016
Offline
Thanks! With the selection rule applied to the node before it worked.
I still got the following warning: “Read lock failed because of existing lock” but after looking at the example of diming the lights I learned that one should get the stage after doing the selections.

Cheers!
User Avatar
Member
86 posts
Joined: Jan. 2015
Offline
I tried scanning through the docs, but I couldn't find any explanation as to what "Read lock failed because of existing lock" either - @mtucker is there an explanation anywhere as to what that means, and/or how Houdini is handling the UsdStage such that such a warning is necessary?
User Avatar
Member
240 posts
Joined: Oct. 2014
Offline
I have to admit I still see this "Read lock failed because of existing lock" message from time. I am uncertain 1) what it actually means, 2) how it's really effecting performance and 3) what I'm supposed to do about it.
- Tim Crowson
Technical/CG Supervisor
User Avatar
Member
8 posts
Joined: Oct. 2021
Offline
jsmack
instead of hou.pwd(), what about the input node?

Edit:
I get a warning about a read lock fail due to existing lock when I tried it. Not sure how it's supposed to be used.
Hi! Any updates on what this warning means and how to deal with it?
User Avatar
Member
55 posts
Joined: Nov. 2019
Offline
Tim Crowson
I have to admit I still see this "Read lock failed because of existing lock" message from time. I am uncertain 1) what it actually means, 2) how it's really effecting performance and 3) what I'm supposed to do about it.
Same, would be awesome to get a deeper understanding on this topic. Thanks!
User Avatar
Staff
451 posts
Joined: June 2020
Offline
A chain of LOP nodes effectively shares a USD stage and we do some on-the-fly mutation as the user jumps around the nodegraph (or makes API calls to access the stage at different nodes). When you call stage()or editableStage(), we perform the necessary mutation to ensure the shared stage has the right composition for the node you called that method on. We then lock things so you can get a consistent view of the stage for the lifetime of your variable without it further mutating under your feet.

What this means, though, is if you *also* ask for the stage from a different point in the LOP chain, we can't just do a cheap(/cheapish) mutation, we have to recompose a whole new stage for you, so that you have both the original stage and now this new one.

You may be looking at your script and saying "I'm not calling stage()/editableStage()multiple times!", but you may be triggering the same effect through other calls - selection rule expansion is the one we most commonly see. If we consider the "Dim the lights" example for the Python LOP, there's a block:
ls = hou.LopSelectionRule()
ls.setPathPattern('%type:Light')
paths = ls.expandedPaths(node.inputs()[0])

That last line (the expandedPathsline) is effectively asking for the stage from node.inputs()[0], so if you've previously asked for the stage from node, you've just run into the "need to recompose a whole new stage for you" situation.

We generally advise doing as much reading up-front as possible (and, if necessary, scoping your variables to help release locks as early as possible) and only calling editableStage()when you truly need to do the authoring.

Something else we added in Houdini 19.5, which we've perhaps not advertised well enough, is the ability to evaluate selection rules directly against stages rather than nodes (from which we internally extract a stage). So if you've already run something like theLockedStage = node.editableStage()you can call ls.expandedPaths(stage=theLockedStage)without the recomposition hit.

I hope this offers better insight into the warning you're getting. Do take it seriously with larger scenes; recomposition can be very expensive.
User Avatar
Member
240 posts
Joined: Oct. 2014
Offline
Cheers Rob! Thanks for so much for explaining that!
- Tim Crowson
Technical/CG Supervisor
User Avatar
Member
55 posts
Joined: Nov. 2019
Offline
robp_sidefx
We generally advise doing as much reading up-front as possible (and, if necessary, scoping your variables to help release locks as early as possible) and only calling editableStage()when you truly need to do the authoring.

So this means that for now, if we need to access stage to get the data for setPathParent(), there is no way around it. We have to call stage at least twice.

robp_sidefx
Something else we added in Houdini 19.5, which we've perhaps not advertised well enough, is the ability to evaluate selection rules directly against stages rather than nodes (from which we internally extract a stage). So if you've already run something like theLockedStage = node.editableStage()you can call ls.expandedPaths(stage=theLockedStage)without the recomposition hit.

This seems like it will be very useful indeed.

robp_sidefx
I hope this offers better insight into the warning you're getting. Do take it seriously with larger scenes; recomposition can be very expensive.

Definitely. Thank you so much.
Edited by Cicuta - July 4, 2023 06:19:24
User Avatar
Staff
451 posts
Joined: June 2020
Offline
Cicuta
So this means that for now, if we need to access stage to get the data for setPathParent(), there is no way around it. We have to call stage at least twice.

If you're willing to share your script/hip here (or via support), I'd be happy to take a look.
User Avatar
Member
55 posts
Joined: Nov. 2019
Offline
That's so nice of you. You are already familiar with what I was trying to do from this post here:https://www.sidefx.com/forum/topic/82343/?page=1#post-394926. [www.sidefx.com] My goal is getting "All the bound geometry" from a material that matches an expression, in this case whenever a material has a node with a specific key in it. Without a python equivalent to the primitive pattern %geofrommat, my only guess for doing this through python was using the suggested setPathParent() method in that very same post. In doing so, since the objective is dynamic, I need to access the primitives first to fill the information of the setPathParent() which is exactly where I get the warning.
The attachment was my first approach. Thank you so much!

(The file is working with arnold materials)
Edited by Cicuta - July 4, 2023 11:23:52

Attachments:
geofrommatPY.hip (434.3 KB)

User Avatar
Staff
451 posts
Joined: June 2020
Offline
Right ... so this is a good example where ls.expandedPaths(node.inputs()[0])can be replaced with ls.expandedPaths(stage=stage)and the warning will go away.

Alternatively, here's the script re-written into discrete read/write blocks:

node = hou.pwd()
from pxr import Usd, UsdGeom, UsdShade

# SHARED

coll_path = "/collections/fx"
bound_list = []

# READING

stage = node.inputs()[0].stage()
coll = stage.GetPrimAtPath(coll_path)
coll_api = Usd.CollectionAPI(coll, "key")
key_coll = coll_api.GetIncludesRel()

targets = key_coll.GetTargets() 
for target in targets:
    material_path = target.GetParentPath()
    material = stage.GetPrimAtPath(material_path)
    ls = hou.LopSelectionRule()
    expression = "%geofrommat:" + str(material.GetPath())
    ls.setPathPattern(expression)
    bound = ls.expandedPaths(node.inputs()[0])[0]  # or replace "node.inputs()[0]" with "stage=stage"
    bound_list.append(str(bound))

# WRITING

stage = node.editableStage()
coll = stage.GetPrimAtPath(coll_path)
coll_api = Usd.CollectionAPI(coll, "bound")
bound_coll = coll_api.GetIncludesRel()

bound_coll.SetTargets(bound_list)        
User Avatar
Member
55 posts
Joined: Nov. 2019
Offline
Oh I didn't think of the
stage = node.inputs()[0].stage()
line. Makes a lot of sense. Thanks a lot!! Unfortunately I am locked in h.19 right now so I cannot use the ls.expandedPaths(stage=stage) trick right now, but will note it. Amazing.

Now that I have the chance, what is the programmatic logic behind the %geofrommat pattern/"Select All Bound Geometry"? Are there plans on having something similar in python or VEX?

Thanks again!
Edited by Cicuta - July 4, 2023 16:37:42
User Avatar
Staff
451 posts
Joined: June 2020
Offline
Cicuta
what is the programmatic logic behind the %geofrommat pattern/"Select All Bound Geometry"?

It's part of the public Github repo, so I'll take the easy way out here and say "have a look for yourself"
https://github.com/sideeffects/HoudiniUsdBridge/blob/houdini19.5/src/houdini/lib/H_USD/HUSD/XUSD_AutoCollection.C#L1778-L1857 [github.com]

Are there plans on having something similar in python or VEX?

Can you elaborate a bit more on what's missing for you in Python? Where are you finding it problematic to construct & evaluate a selection rule?
User Avatar
Member
55 posts
Joined: Nov. 2019
Offline
robp_sidefx
It's part of the public Github repo, so I'll take the easy way out here and say "have a look for yourself"
https://github.com/sideeffects/HoudiniUsdBridge/blob/houdini19.5/src/houdini/lib/H_USD/HUSD/XUSD_AutoCollection.C#L1778-L1857 [github.com]

Awesome!

It was not related with contruct & evaluate a selection rule, that was the remedy. Going back to this topic: https://www.sidefx.com/forum/topic/82343/?page=1#post-394926, [www.sidefx.com] I haven't been able to find something like %geofrommat in python, like I have for %matfromgeo (https://openusd.org/release/api/class_usd_shade_material_binding_a_p_i.html#a5602550a78f68f6a1d1bf62187e22edd).
But now reading the repo you sent I think I have an idea of what its doing.

Thanks! This has been truly revealing!
Edited by Cicuta - July 5, 2023 05:18:42
  • Quick Links