AndrewJBeard
AndrewJBeard
About Me
Connect
LOCATION
Not Specified
WEBSITE
Houdini Skills
Availability
Not Specified
Recent Forum Posts
Making digital assets: handling internal attributes / groups Oct. 4, 2022, 3:15 p.m.
I'm starting to get back into developing custom digital assets to fill some gaps in Houdini's out-of-box (and Labs) operator set. Many of these will be assets built from other nodes, particularly in SOPs, and I'll be creating and manipulating geometry attributes and groups internally within the asset. Whenever this happens, there's a risk that attribute and group names collide with existing names on the input geometry, potentially leading to undesirable behaviour within the asset. I've been wrestling with how to handle this in a way that is robust and transparent to the user, and thought I'd share my thinking here for comment. The options I've come up with so far are:
Ignore the problem
Use whatever attribute / group names make sense to me and overwrite any identically-named attributes / groups that the user has unwittingly supplied as input geometry. Not a particularly forgiving experience for the user, and could easily lead to confusion when things don't work as expected.
Obfuscate the internal names
I've lifted the lid on some Labs assets and noticed a tendency (but not quite frequent enough to be considered a rule) to prefix internal names with single or double underscores, a bit like how python 'hides' class internals. If this (or something similar) was an established practice that Houdini users knew and adhered to, this would probably work quite well and I wouldn't need to think any more on the problem. But it isn't, as far as I can tell (please correct if you know otherwise; the Labs assets may be trying to establish a precedent here). And there remains the possibility that a user who is unaware of such a convention or perhaps imports geometry from another package with conflicting attribute/group names that unknowingly interfere with the asset internals.
Raise an error / warning
With prefixed or otherwise obfuscated internal names for attributes/groups, for the rare occasions that a naming conflict does arise, the asset could simply raise an error or warning about a name collision. That puts the onus on the user to fix it by renaming one or more attribute/group names, which is better than silently ignoring the collision, but still feels like a suboptimal experience for a user in that position.
Procedurally rename internal names upon collision
This is the approach I've settled on thus far, and seems the most Houdini-like and acceptable from a user perspective, and introduces only moderate inconvenience to an asset developer. It works by branching the asset input geometry into a custom Python SOP, into which I list all the internal attribute and group names I want to use. The Python code then checks each name against the incoming geometry, and appends/increments the name by one if there is a collision - just like node names do when you copy-paste them or try to create a node name conflict - until it finds a unique name. The Python code then creates a dictionary attribute at the global geometry (detail) level with desired names as the keys (e.g. 'uv') and resulting names after collision-testing as the values (e.g. 'uv1').
Why store the mapping in an attribute? Well, the deconflicted names need to be referenced in string parameters of other nodes, and potentially in VEX or other Python code elsewhere in the asset, and there are established ways of doing this that don't require custom functions to be written. And the detail attribute itself does not propagate any further through the network, since it terminates that branch and is only indirectly referenced by the output geometry pipeline.
And so instead of referencing the original attribute / group names directly in node parameters (and any VEX/Python code within the asset), I instead retrieve the corresponding dictionary value from the detail attribute in the other branch, using the original name as key. Fully procedural, and guaranteed not to result in name collisions at runtime, regardless of whatever attribute or group names exist on the input geometry. It does, however, necessitate Python's slighty more verbose channel referencing syntax, because I haven't yet found a way to get Hscript / Expressions to work with dictionary attributes (again, would welcome any advice to the contrary).
With this approach, an asset developer can focus on getting the asset working right, using whatever internal attribute and group names make sense, and append these to the list of names in the custom Python SOP as they go. As development nears completion, one needs to then convert any hard-coded attribute/group names into references to the detail dictionary, but that's fairly trivial and could well be automated with a script (which I haven't bothered with owing to the relative simplicity of the assets I'm developing).
Anyway, that's probably enough detail on this admittedly niche topic for now. If you've made it this far, I'd be interested any thoughts / approaches to this problem you've come up with, and whether procedural renaming is the most sensible solution. If any devs are purusing the forum, perhaps there could be some built-in functionality to deal with attribute/group naming conflicts, that either builds on this solution or tackles it a completely different way.
Ignore the problem
Use whatever attribute / group names make sense to me and overwrite any identically-named attributes / groups that the user has unwittingly supplied as input geometry. Not a particularly forgiving experience for the user, and could easily lead to confusion when things don't work as expected.
Obfuscate the internal names
I've lifted the lid on some Labs assets and noticed a tendency (but not quite frequent enough to be considered a rule) to prefix internal names with single or double underscores, a bit like how python 'hides' class internals. If this (or something similar) was an established practice that Houdini users knew and adhered to, this would probably work quite well and I wouldn't need to think any more on the problem. But it isn't, as far as I can tell (please correct if you know otherwise; the Labs assets may be trying to establish a precedent here). And there remains the possibility that a user who is unaware of such a convention or perhaps imports geometry from another package with conflicting attribute/group names that unknowingly interfere with the asset internals.
Raise an error / warning
With prefixed or otherwise obfuscated internal names for attributes/groups, for the rare occasions that a naming conflict does arise, the asset could simply raise an error or warning about a name collision. That puts the onus on the user to fix it by renaming one or more attribute/group names, which is better than silently ignoring the collision, but still feels like a suboptimal experience for a user in that position.
Procedurally rename internal names upon collision
This is the approach I've settled on thus far, and seems the most Houdini-like and acceptable from a user perspective, and introduces only moderate inconvenience to an asset developer. It works by branching the asset input geometry into a custom Python SOP, into which I list all the internal attribute and group names I want to use. The Python code then checks each name against the incoming geometry, and appends/increments the name by one if there is a collision - just like node names do when you copy-paste them or try to create a node name conflict - until it finds a unique name. The Python code then creates a dictionary attribute at the global geometry (detail) level with desired names as the keys (e.g. 'uv') and resulting names after collision-testing as the values (e.g. 'uv1').
Why store the mapping in an attribute? Well, the deconflicted names need to be referenced in string parameters of other nodes, and potentially in VEX or other Python code elsewhere in the asset, and there are established ways of doing this that don't require custom functions to be written. And the detail attribute itself does not propagate any further through the network, since it terminates that branch and is only indirectly referenced by the output geometry pipeline.
And so instead of referencing the original attribute / group names directly in node parameters (and any VEX/Python code within the asset), I instead retrieve the corresponding dictionary value from the detail attribute in the other branch, using the original name as key. Fully procedural, and guaranteed not to result in name collisions at runtime, regardless of whatever attribute or group names exist on the input geometry. It does, however, necessitate Python's slighty more verbose channel referencing syntax, because I haven't yet found a way to get Hscript / Expressions to work with dictionary attributes (again, would welcome any advice to the contrary).
With this approach, an asset developer can focus on getting the asset working right, using whatever internal attribute and group names make sense, and append these to the list of names in the custom Python SOP as they go. As development nears completion, one needs to then convert any hard-coded attribute/group names into references to the detail dictionary, but that's fairly trivial and could well be automated with a script (which I haven't bothered with owing to the relative simplicity of the assets I'm developing).
Anyway, that's probably enough detail on this admittedly niche topic for now. If you've made it this far, I'd be interested any thoughts / approaches to this problem you've come up with, and whether procedural renaming is the most sensible solution. If any devs are purusing the forum, perhaps there could be some built-in functionality to deal with attribute/group naming conflicts, that either builds on this solution or tackles it a completely different way.
Attaching geometry to objects in DOPs Feb. 2, 2015, 1:20 p.m.
I've got a tower of bricks in DOPs being collapsed a Magnet force, which itself references metaballs in a geometry node. At the moment the metaballs are static and don't move with the collapsing bricks, which is fine but I'd like to activate each metaball force at different times during the simulation, so it's best if they follow the simulated objects. How do I ‘attach’ the metaballs to certain bricks as they collapse so that the force they create moves with these bricks?
Is it effectively a constraint I need to set up (in which case I'm not sure that the constraint geometry required by the Bullet solver will work) or is there a simpler way? I don't need the metaballs to participate in the RBD simulation other than act sources of force to be applied to the RBD objects.
Thanks in advance,
Andrew
Is it effectively a constraint I need to set up (in which case I'm not sure that the constraint geometry required by the Bullet solver will work) or is there a simpler way? I don't need the metaballs to participate in the RBD simulation other than act sources of force to be applied to the RBD objects.
Thanks in advance,
Andrew
Varying Instanced Geometry Jan. 15, 2015, 3:58 p.m.
I've got a bunch of identical objects all wrapped up as a packed primitive, having been instanced by the Copy SOP. (A bunch of bricks stacked up in a tower ready for collapsing in DOPs, if you're interested). Nothing complex.
I'd like to vary the color (and nothing more) of each primitive, which I would have thought is accomplished by simply adding a Cd attribute to the points which represent the instanced geometry, and throwing a material shader at the object.
Sadly not.
I understand that both the Viewport and Mantra do something special with packed primitives (and other forms of instancing) that requires only one copy of the geometry to be retained in memory for efficiency and whatnot. But surely there's a way to add unique color to each instance?
Do I have to unpack my packed primitive in order to apply color to each primitive? Is there some limitation of instancing at the *geometry* level that prevents point attributes like color being used in shaders? Does it only work when instancing at the *object* level (which is what most of the H13 documentation on the subject seems to refer to)? Although, that said, I've tried both and had no luck with either.
Really thought I was just getting to grips with packed primitives until now. Please help. My colorless bricks are beginning to look a little sad
I'd like to vary the color (and nothing more) of each primitive, which I would have thought is accomplished by simply adding a Cd attribute to the points which represent the instanced geometry, and throwing a material shader at the object.
Sadly not.
I understand that both the Viewport and Mantra do something special with packed primitives (and other forms of instancing) that requires only one copy of the geometry to be retained in memory for efficiency and whatnot. But surely there's a way to add unique color to each instance?
Do I have to unpack my packed primitive in order to apply color to each primitive? Is there some limitation of instancing at the *geometry* level that prevents point attributes like color being used in shaders? Does it only work when instancing at the *object* level (which is what most of the H13 documentation on the subject seems to refer to)? Although, that said, I've tried both and had no luck with either.
Really thought I was just getting to grips with packed primitives until now. Please help. My colorless bricks are beginning to look a little sad