Jump to content
Sign in to follow this  
magneto

How to get the top object path from the geometry level?

Recommended Posts

I am using the origin expression to do some calculations inside an HDA but I noticed using ".", "..", etc doesn't give me the same result as using "/obj/firstObject" for the first object:

origin("/obj/firstObject", "/obj/secondObject")

So I hardcoded the path relatively using "../../", but this only works if the HDA is created at the top geometry level. If you create it inside a subnet, then it doesn't work.

So I am wondering if there is a way to specify the top level object path from the geometry level so it would always give me "/obj/firstObject" wherever I am inside the geometry path?

Thanks :)

Edited by magneto

Share this post


Link to post
Share on other sites

I'm not sure I fully understand what you are experiencing, but have you tried the opfullpath() expression?

opfullpath("..")

-dennis

Edited by dennis.weil

Share this post


Link to post
Share on other sites

Thanks Dennis. I have attached a file showing the issue.

Basically if you look at the numeric fields, the first one shows 10 which is correct, the second one shows 5, which is wrong.

It uses the origin expression, and it only works if I provide the full path for the first argument. Since HDAs created from subnets goes one level deeper frm the geometry level, I had to use "../../" for the first argument of origin.

But if after I create this asset, someone creates it in another subnet, then "../../" no longer returns the top level path "/obj/box". So I need a way to get this path regardless of where I am in the network, but don't want to have another field on the asset because it's the object itself.

origin.hip

Share this post


Link to post
Share on other sites

Basically you need to be able to traverse upwards from a given node until you find that nodes containing object node and then return the path to that. That is extremely easy to do in Python though not as fun in Hscript expressions. For example:

def findParentObject(node):
    """ Find the first parent node that is an object node. """
    # The node is an object node so return it.
    if isinstance(node, hou.ObjNode):
        return node
    # Get the parent of the node.
    parent = node.parent()
    # If there is no parent then we have failed, so return None.
    if not parent:
        return None
    # Check the parent node.
    return findParentObject(parent)

  • Like 2

Share this post


Link to post
Share on other sites

Ah, I see. One solution might be to use python and loop through each network level until you hit /obj. In that case you print the path of the last node you checked.

I created an example for you. If you are going to create a digital asset you can exchange the while condition with any path you want.

-dennis

origin_python.hip

  • Like 1

Share this post


Link to post
Share on other sites

Thanks guys, very helpful. I wouldn't think of doing this because I thought there would be a magic expression for this, something like optoplevelpath() :)

Share this post


Link to post
Share on other sites

Graham was just a little bit faster than me :)

The benefit of doing it this way is you don't have to go to the topmost level if you don't want to. In case of a digital asset, which itself does not move but contains moving geo nodes, going up all the way would not help.

-dennis

Share this post


Link to post
Share on other sites

I have a philosophy (surprise surprise) that if you build a tool in SOPs to do some heavy lifting, assume the user has a bit of Houdini skills under their belt. I know I am not answering your question but questioning the design.

I am on the side that exposes the path to the user and let them override to pick up any object's transform that they so wish and not obscure a critical part of your tool. Give it a sane default as you have mentined: ".."

Have a look at the new Fluid Source SOP which is one of those higher level SOPs that incorporates a tremendous amount of high level functionality. More specficially have a look at the Object based velocity logic in the Velocity Volumes tab. When enabled, it exposes the object path as "..".

Internally it uses Python expressions on a Volume Velocity SOP to do the equivallent of the origin function (if you want to use python that is instead of the origin() expression).

For a brief example of using transforms in Python (which is one of the few times I back out of hscript and use Python for these days), look at:

http://localhost:48626/hom/cookbook/object_xform/

Check it out.

----

To answer your question, if you choose to use Python to fetch the object path, it is straightforward to work in the logic to test if the current directory you are in is an object based directory and not a SOP based directory as you claw your way up out of your asset if you want to Fisher Price things. DOPs does a lot of this. For example the Center Of Mass Python expression on the RBD Object off-the-shelf does a lot of this auto-comparing in-line to return the COM for each DOP object created based on the origin of the object.

In your case, you could add a new object path parameter (set to Python type), set a key and type in:

n = pwd()
obj = n.parent()
while obj.type().category() != hou.objNodeTypeCategory():
    obj = obj.parent()
return obj.path()

then simply channel reference in to origin() or vtorigin() with expression:

vtorigin("",chs("parent_obj"))[0]

for the X transform of the parent object.

Finally not only do you have an expression to fetch the object parent path automagically, the end user can blow this expression away if he/she chooses and define their own path manually.

Win-win.

See the attached example file.

test_for_object_in_sop_parm.hip

  • Like 1

Share this post


Link to post
Share on other sites

Thanks old school for your detailed reply, appreciate it alot. I understand your idea of making things more open and flexible, which is definitely the Houdini way. I didn't want to expose that parameter because my asset is very similar to Graham's Transform by Object which transforms the current object by another object. So since it's the current object you are transforming, I didn't expose it as a parameter.

But I am definitely with you on making things as open as possible, and not black box it :)

Share this post


Link to post
Share on other sites

Basically you need to be able to traverse upwards from a given node until you find that nodes containing object node and then return the path to that. That is extremely easy to do in Python though not as fun in Hscript expressions. For example:

def findParentObject(node):
""" Find the first parent node that is an object node. """
# The node is an object node so return it.
if isinstance(node, hou.ObjNode):
return node
# Get the parent of the node.
parent = node.parent()
# If there is no parent then we have failed, so return None.
if not parent:
return None
# Check the parent node.
return findParentObject(parent)

it's really nice to solver this problem as very well !!

Thanks!!

Share this post


Link to post
Share on other sites

here is a python oneliner for those who want to use it in an expression format:

 

top_network_node = hou.node('/'.join(node.path().split('/',3)[:3]))

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×