Thank you for that example. It was very helpful.
I have to say, though, that this VEX-based approach to things is incredibly obtuse and inconvenient compared to the older methods that the old Point and Group SOPs used to provide. This is especially true for setups that aren't overly complex or slow to cook. Many times, clarity of intent–which a simple expression like “($BBZ < .95) && ($BBZ > 1.0)” expresses very clearly and succinctly–is preferred over an esoteric collection of multi-parms like in the Group by Expression SOP which happens to execute faster.
Found 53 posts.
Search results Show results as topic list.
Technical Discussion » Equivalent of old Group SOP expressions?
- jrcooper
- 59 posts
- Offline
Technical Discussion » Equivalent of old Group SOP expressions?
- jrcooper
- 59 posts
- Offline
So one thing I find intensely annoying in H18 is the lack of expression capabilities in the new Group SOP. What, for example, is the new syntax for the following expression from the old Group SOP?
($BBZ < 1.0) && ($BBZ > 0.95)
I'd like to make a group out of all the points whose Z bounding box coordinate is less than 1.0 but greater than 0.95. Even assuming I go to the (tedious) trouble to create an attribute called, say, BB to store the bounding box values (because the new Group SOP does not allow referencing locals anymore), I still can't seem to put compound conditionals in the Base Group parm like this:
@BB.z<1.0&&@BB.z>0.95
Not only is this horribly unreadable thanks to the inability to use spaces in the new expression syntax, it doesn't even work.
Alternatively, is there a way to drop down the old Group SOP in H18?
($BBZ < 1.0) && ($BBZ > 0.95)
I'd like to make a group out of all the points whose Z bounding box coordinate is less than 1.0 but greater than 0.95. Even assuming I go to the (tedious) trouble to create an attribute called, say, BB to store the bounding box values (because the new Group SOP does not allow referencing locals anymore), I still can't seem to put compound conditionals in the Base Group parm like this:
@BB.z<1.0&&@BB.z>0.95
Not only is this horribly unreadable thanks to the inability to use spaces in the new expression syntax, it doesn't even work.
Alternatively, is there a way to drop down the old Group SOP in H18?
Technical Discussion » op:/ operator and Camera background image?
- jrcooper
- 59 posts
- Offline
Yes, I tried that too:
op:/img/solid_bkgd/color1
…same error message:
Error: Unrecognized file type “op:/img/solid_bkgd/color1”.
op:/img/solid_bkgd/color1
…same error message:
Error: Unrecognized file type “op:/img/solid_bkgd/color1”.
Technical Discussion » op:/ operator and Camera background image?
- jrcooper
- 59 posts
- Offline
So I hate to repeat this thread subject, but the previous one is marked as CLOSED and yet there doesn't appear to be any resolution to this issue.
Does the Background Image parm of a Camera not support op:/ data node references, in particular op:/img/… references? I'd like to simply add a solid color, or maybe a procedural pattern, generated out of the COP2 /img context as the background of my renders without having to litter my hard drive with tiny jpeg files.
I tried putting a simple op:/img/solid_bkgd reference into that parm but when I render I just get an error about unknown file type. Am I typing this reference incorrectly? Or does this still not work properly?
Does the Background Image parm of a Camera not support op:/ data node references, in particular op:/img/… references? I'd like to simply add a solid color, or maybe a procedural pattern, generated out of the COP2 /img context as the background of my renders without having to litter my hard drive with tiny jpeg files.
I tried putting a simple op:/img/solid_bkgd reference into that parm but when I render I just get an error about unknown file type. Am I typing this reference incorrectly? Or does this still not work properly?
Technical Discussion » VEX equivalent to picni() in SOP context?
- jrcooper
- 59 posts
- Offline
Ah, the “wrap” keyword argument does help simplify the VEX expression somewhat:
Thanks!
(BTW, the Attribute From Map SOP doesn't have “edge” or “clamp” type wrapping options, so I'll be sticking with the above VEX expression in an Attribute Expression SOP.)
rawcolormap("op:" + opfullpath("../artwork/OUT"), relpointbbox(0, @P).x, 1 - relpointbbox(0, @P).z, "wrap", "edge")
Thanks!
(BTW, the Attribute From Map SOP doesn't have “edge” or “clamp” type wrapping options, so I'll be sticking with the above VEX expression in an Attribute Expression SOP.)
Technical Discussion » VEX equivalent to picni() in SOP context?
- jrcooper
- 59 posts
- Offline
So I think I figured out a solution (using an Attribute Expression node):
Setting the Color (Cd) attribute to:
I had to clamp the bounding box values to 0.9999 because rawcolormap() wraps a value of 1.0 around to 0.0, an annoying behavior that picni() does not exhibit.
This is a lot harder to read than the hscript expression it replicates. I hope it has superior performance to make up for that.
Setting the Color (Cd) attribute to:
rawcolormap("op:" + opfullpath("../artwork/OUT"), min(relpointbbox(0, @P)[0], 0.9999), min(1 - relpointbbox(0, @P)[2], 0.9999))
I had to clamp the bounding box values to 0.9999 because rawcolormap() wraps a value of 1.0 around to 0.0, an annoying behavior that picni() does not exhibit.
This is a lot harder to read than the hscript expression it replicates. I hope it has superior performance to make up for that.
Edited by jrcooper - April 29, 2020 17:05:33
Technical Discussion » VEX equivalent to picni() in SOP context?
- jrcooper
- 59 posts
- Offline
So I'm trying to wrap my head around VEX coding for use in the Attribute Wrangle node in SOP context and I need a function like the hscript picni() function in order to do a pixel color lookup from a COP2 node. Using the old Point SOP, I would have used an expression like this (to, for example, set the red channel of the Cd attribute):
Where artwork is a COP2 network and OUT is simply a Null node at the end of the comp nodes yielding the final image to use for pixel lookups.
So what is the equivalent of that in SOP-context VEX code?
@Cd.r = what do I put here?
picni("../artwork/OUT", $BBX, 1 - $BBZ, D_CR)
Where artwork is a COP2 network and OUT is simply a Null node at the end of the comp nodes yielding the final image to use for pixel lookups.
So what is the equivalent of that in SOP-context VEX code?
@Cd.r = what do I put here?
Technical Discussion » Parm callbacks and environment variables
- jrcooper
- 59 posts
- Offline
I have a custom HDA with an Integer parm that has a callback script defined for it. If I set the value of this parm to an environment variable like $VEHICLE_ID (I guess this becomes an hscript expression), and then change $VEHICLE_ID in a textport like this:
/ -> setenv -g VEHICLE_ID = 5
/ -> varchange
I see that the evaluated value of this parm is now 5, but the change in value does not trigger the parm's callback script to run.
How can I get the callback script to run when the parm's value changes as a result of a change to the global variable that is set as its expression/value?
Thanks!
/ -> setenv -g VEHICLE_ID = 5
/ -> varchange
I see that the evaluated value of this parm is now 5, but the change in value does not trigger the parm's callback script to run.
How can I get the callback script to run when the parm's value changes as a result of a change to the global variable that is set as its expression/value?
Thanks!
Technical Discussion » HOUDINI_OPNAMESPACE_HIERARCHY not working as expected
- jrcooper
- 59 posts
- Offline
Technical Discussion » Using $SF in custom ROP OTL parms
- jrcooper
- 59 posts
- Offline
Well, $SF exists at the top level of a Dynamics ROP because you can, and must, use it in the dopoutput (“Output File”) parm if you want the “Output Every Sim Frame Using $SF” checkbox to have any effect.
My expectation is that if $SF exists at the top level of a Dynamics ROP, then there ought to be a way (for SideFX) to make it available at the top level of a custom ROP OTL that contains one, so that the dopoutput parm can be promoted to the OTL's interface and work accordingly.
My expectation is that if $SF exists at the top level of a Dynamics ROP, then there ought to be a way (for SideFX) to make it available at the top level of a custom ROP OTL that contains one, so that the dopoutput parm can be promoted to the OTL's interface and work accordingly.
Technical Discussion » Using $SF in custom ROP OTL parms
- jrcooper
- 59 posts
- Offline
I am having a bit of difficulty with the $SF variable which needs to appear in the Output File parm of a custom ROP OTL that has a Dynamics ROP inside of it. I am trying to link the Dynamics ROP's Output File parm (dopoutput) to the top level of the OTL, but Houdini refuses to recognize $SF in that context.
Consequently, the $SF evaluates to an empty string and so the dopoutput path of the Dynamics ROP inside the OTL ends up with no frame token. The expression in the Dynamics node's dopoutput parm is chs(“../dopoutput”).
Is there a way to get Houdini to recognize $SF at the top level of an OTL so that it evaluates properly in the Dynamics ROP inside? Preferably without a bunch of string replacement voodoo in the expression inside. That tends to be fragile given all the unpredictable ways a path can be constructed/expressed on the top-level dopoutput parm.
Thanks!
Consequently, the $SF evaluates to an empty string and so the dopoutput path of the Dynamics ROP inside the OTL ends up with no frame token. The expression in the Dynamics node's dopoutput parm is chs(“../dopoutput”).
Is there a way to get Houdini to recognize $SF at the top level of an OTL so that it evaluates properly in the Dynamics ROP inside? Preferably without a bunch of string replacement voodoo in the expression inside. That tends to be fragile given all the unpredictable ways a path can be constructed/expressed on the top-level dopoutput parm.
Thanks!
Technical Discussion » HOUDINI_OPNAMESPACE_HIERARCHY not working as expected
- jrcooper
- 59 posts
- Offline
I have an OTL called cool_thing.otl with several versions inside it:
com.jrcooper::cool_thing::0.1.6
com.jrcooper::cool_thing::0.1.5
com.jrcooper::cool_thing::0.1.4
:
com.jrcooper::cool_thing::0.1.0
According to the docs for Houdini 12+, setting the environment variable HOUDINI_OPNAMESPACE_HIERARCHY to a specific OTL definition will cause Houdini to create nodes of that type by default. For example, I would expect that if I set:
HOUDINI_OPNAMESPACE_HIERARCHY=com.jrcooper::cool_thing::0.1.5
…and then launch Houdini and do this (note the ambiguous reference):
opadd cool_thing
…that I would get a cool_thing node using the 0.1.5 definition. Instead I get the latest version, 0.1.6. I also get the latest version from the usual TAB menu method of creating the node. I have confirmed that the environment variable is indeed set to the given value by interrogating with os.environ.get() in the Python shell.
Does anyone know how to properly use HOUDINI_OPNAMESPACE_HIERARCHY? Am I not understanding the documentation when it says:
com.jrcooper::cool_thing::0.1.6
com.jrcooper::cool_thing::0.1.5
com.jrcooper::cool_thing::0.1.4
:
com.jrcooper::cool_thing::0.1.0
According to the docs for Houdini 12+, setting the environment variable HOUDINI_OPNAMESPACE_HIERARCHY to a specific OTL definition will cause Houdini to create nodes of that type by default. For example, I would expect that if I set:
HOUDINI_OPNAMESPACE_HIERARCHY=com.jrcooper::cool_thing::0.1.5
…and then launch Houdini and do this (note the ambiguous reference):
opadd cool_thing
…that I would get a cool_thing node using the 0.1.5 definition. Instead I get the latest version, 0.1.6. I also get the latest version from the usual TAB menu method of creating the node. I have confirmed that the environment variable is indeed set to the given value by interrogating with os.environ.get() in the Python shell.
Does anyone know how to properly use HOUDINI_OPNAMESPACE_HIERARCHY? Am I not understanding the documentation when it says:
You can add a fully-qualified name to the list to make it take precedence even over a later version. For example, adding com.sundae::vines::1.0 to the list would make Houdini use that for an ambiguous vines reference, even if com.sundae::vines::2.0 is available.Thanks!
Technical Discussion » Bringing up the color editor via python
- jrcooper
- 59 posts
- Offline
What is the recommended method for utilizing PyQt within a Houdini python script? The following (placed in a shelf button tool) just segfaults Houdini 12:
import PyQt4.Qt as qt
c = qt.QColorDialog.getColor()
print c
import PyQt4.Qt as qt
c = qt.QColorDialog.getColor()
print c
Technical Discussion » Bringing up the color editor via python
- jrcooper
- 59 posts
- Offline
Is there a HOM python function that will bring up a color editor dialog, allow the user to select a color, and return it as an (r,g,b) tuple?
Technical Discussion » HDAModule.setParmTemplateGroup() wiping out parm defaults
- jrcooper
- 59 posts
- Offline
Ah, so this is a Houdini 12-only addition to the HOM. I should have known.
Thanks for pointing it out to me, though. Much appreciated.
Thanks for pointing it out to me, though. Much appreciated.
Technical Discussion » HDAModule.setParmTemplateGroup() wiping out parm defaults
- jrcooper
- 59 posts
- Offline
Well, if we look at the HDK side of this, we can see that PRM_Template objects store PRM_Default objects within them. Examining the documentation for the PRM_Default constructor reveals the following interesting bit of info:
PRM_Default:RM_Default (float thefloat = 0.0F,
const char * thestring = 0,
CH_StringMeaning string_meaning = CH_AUTO_DETECT_OLD_EXPRESSION
)
PRM_Default:RM_Default (float thefloat = 0.0F,
const char * thestring = 0,
CH_StringMeaning string_meaning = CH_AUTO_DETECT_OLD_EXPRESSION
)
PRM_Default has two parts: a float and a string. For floating point parameters, if the default string is defined, then the parameter will start off being animated and have the channel expression defined by the string. Otherwise, the floating point default is used for float and integer types, while the string is used to initialize string types.This conforms to the behavior you described. If we call PRM_Template::getDefault() on a PRM_Template object, we would expect to get back an object containing the expression string (e.g., “$FSTART”) that represents the default value. The real question is what is the python equivalent to this PRM_Default object, and how do we access it?
Technical Discussion » HDAModule.setParmTemplateGroup() wiping out parm defaults
- jrcooper
- 59 posts
- Offline
Technical Discussion » HDAModule.setParmTemplateGroup() wiping out parm defaults
- jrcooper
- 59 posts
- Offline
Technical Discussion » HDAModule.setParmTemplateGroup() wiping out parm defaults
- jrcooper
- 59 posts
- Offline
Okay, maybe a better question is this: where do the default parm values/expressions get stored in hou.ParmTemplate objects? You would think it would be in the default_value tuple, but apparently not.
Example:
Suppose I add an Integer parm to my OTL called fps. I go to the Channels tab in the Parameter Description section of the Type Properties dialog and set its default value to the expression $FPS. When I click Accept, I see the new parm on the node that is an instance of my OTL and it has $FPS as its default expression/value.
However, if I run the following python code to interrogate the ParmTemplates on this OTL, I see that the default_value tuple for the fps parm is (0,):
parmLayout = node.type().definition().parmTemplateGroup()
for parmTemplate in parmLayout.entries():
print parmTemplate
The printed form of the fps ParmTemplate is this:
<hou.IntParmTemplate name='fps' label='FPS' length=1 naming_scheme=Base1 default_value0,)>
So where is the fact that $FPS is the default expression for the fps parm being stored? Clearly it must be stored somewhere in the OTL definition because it is set properly when I drop down a new instance of the OTL. And yet, if I change the parmTemplateGroup programatically (like if I add a new parm to it via the python code in my original post), the fact that $FPS is supposed to be the default expression for fps is cleared out somehow.
Surely someone knows what is going on here!
Example:
Suppose I add an Integer parm to my OTL called fps. I go to the Channels tab in the Parameter Description section of the Type Properties dialog and set its default value to the expression $FPS. When I click Accept, I see the new parm on the node that is an instance of my OTL and it has $FPS as its default expression/value.
However, if I run the following python code to interrogate the ParmTemplates on this OTL, I see that the default_value tuple for the fps parm is (0,):
parmLayout = node.type().definition().parmTemplateGroup()
for parmTemplate in parmLayout.entries():
print parmTemplate
The printed form of the fps ParmTemplate is this:
<hou.IntParmTemplate name='fps' label='FPS' length=1 naming_scheme=Base1 default_value0,)>
So where is the fact that $FPS is the default expression for the fps parm being stored? Clearly it must be stored somewhere in the OTL definition because it is set properly when I drop down a new instance of the OTL. And yet, if I change the parmTemplateGroup programatically (like if I add a new parm to it via the python code in my original post), the fact that $FPS is supposed to be the default expression for fps is cleared out somehow.
Surely someone knows what is going on here!
Technical Discussion » HDAModule.setParmTemplateGroup() wiping out parm defaults
- jrcooper
- 59 posts
- Offline
I am trying to write a script for a button that adds a parameter (actually, a copy of a parm from another node) to an (unlocked) OTL definition, and it works except that the call to setParmTemplateGroup() is not only adding the new parm, but clearing out the default values in parm definitions already on the OTL. My code is basically this:
otlDef = otlNode.type().definition()
parmLayout = otlDef.parmTemplateGroup()
newParm = srcNode.parm('creature_name').parmTemplate().clone()
parmLayout.append(newParm)
otlDef.setParmTemplateGroup(parmLayout)
In this case, the OTL that is getting the new parm added happens to also have a number of frame range (int array) parms with default values (expressions) of $FSTART, $FEND. The call to setParmTemplateGroup() clears these default expressions out of their parm definitions and sets them to 0. Could anyone explain why this happens and how I can avoid it?
otlDef = otlNode.type().definition()
parmLayout = otlDef.parmTemplateGroup()
newParm = srcNode.parm('creature_name').parmTemplate().clone()
parmLayout.append(newParm)
otlDef.setParmTemplateGroup(parmLayout)
In this case, the OTL that is getting the new parm added happens to also have a number of frame range (int array) parms with default values (expressions) of $FSTART, $FEND. The call to setParmTemplateGroup() clears these default expressions out of their parm definitions and sets them to 0. Could anyone explain why this happens and how I can avoid it?
-
- Quick Links