Jump to content

Is it possible to use for loops in hscript expressions?


magneto

Recommended Posts

I have a simple expression but it doesn't seem to work but Houdini doesn't tell me what the error is so I am not sure what's wrong. This is the code:


{
id = 1;
for i = 0 to 2
id = 2;
end
return id;
}[/CODE]

The value shown in the parameter is 0, so something is wrong. When I remove the for loop, then it shows 1 correctly.

Any ideas on what's wrong?

Thanks :)

Link to comment
Share on other sites

Thanks a lot Symek, I didn't know hscript and hscript expressions were different :)

Do you know if they have hscript expressions language reference in the help? I only saw the hscript language reference which I assumed was the same used for expressions.

Link to comment
Share on other sites

custom expressions are used to create additional hscript expressions.

I use custom expressions and the custom per-parm expressions somewhat frequently. They are pre-compiled so run very fast, much faster than equivalent python functions. You can bind in hscript commands and expressions easily.

It supports many of the basic data types found in c from ints, floats, strings to arrays.

The first time I was introduced to them big time was in '94 when David Oliver wrote a sliding skin deformed by underlying muscle surfaces for a Dinosaur for a movie of a similar name with a single custom expression in PRISMS. Muscles in Houdini today are inspired by that work and drove things in that direction. That was about a 300 line expression that ran almost real-time.

To learn more about how to write custom expressions, see the help. The doc home page has a link near the bottom to Expressions. Press on that. Then the very first link at the top of the expression page is "how to create your own expressions". Press on that takes you to the main page on writing expressions here:

http://www.sidefx.co...houdini12.1/expressions/_custom

If you just need a single expression in a parameter field, you can ignore the function name and argument list and dive right in to the body of the function with two {}. The only thing you need to make sure is that the return type for the custom expression matches the parameter that is executing the expression. Pretty much limited to ints, floats and strings except for some POP parms that take vectors.

If you write a stand-alone expression, then you can return whatever you want and can use . and [] after the expression to peel out values as with the origin() expression which returns an array of values but can use the "." to access elements of the matrix.

If you write an in-parameter expression that can be re-used, then by all means write a proper expression and save as a text file with an .expr extension for convenience and if you are real old school, you'll use .func which was the PRISMS custom expression extension. Or use the Aliases and Variables... dialog from the main Edit menu and type your custom expression in there.

The hscript commands to manage custom expressions are exls, exread and exrm. Pretty easy to see what they do. It used to be quite common to put exread commands in to 123.cmd and 456.cmd files to make sure they were there all the time. Expression functions are saved inside the hip file btw making them both portable and insidious when you make changes, hence the inclusion in to 456.cmd files to obliterate any versions in the hip file.

The big question is when to use Python and when to use custom expressions. Dunno...

If speed is critical and you just need to push values about including matrices and arrays and VEX/VOPs don't make sense (when wanting to run hscript commands and expressions for example in a parameter), then I'll turn to custom expressions which isn't very often. If you are familiar with c programming, then writing custom expressions will feel quite familiar as they use similar syntax.

For example last night I wanted to do some trig so I wrote a quickie expression function for a complex rotating assembly with rods and pistons. Since speed was important, I turned to expressions instead of python as it was to be run in 20 objects.


{
float rot = (ch("../crank_rotate/rz") + ch("../root_cyl_01/rz") - ch("../strokepath_01/rz")) * -1;
float crankrad = ch("../cylinder_stroke")/2;

float aa = crankrad * cos( rot );
float bb = crankrad * sin( rot );
float dd = sqrt( ch("../rod_length")^2 - bb^2);

return aa + dd;

}[/CODE]

This is way better than writing one long arse expression and runs pretty fast as it's compiled in-line. Reads very nice and is easy to write with alt-e over the parm and the multi-line editor. You can see I declared the floats which is optional in custom expressions but tend to be explicit these days as short-cuts are frowned upon...

If I'm munging strings and values, database stuff, or reading/writing external data and want to leverage the huge library of Python modules with all kinds of hooks, Python it is.

Both Python expressions and custom hscript expressions allow you to write proper functions where you declare and use variables and real conditionals unlike in-line long-as-your-arm hscript expressions (which I do like to do occasionally but will result in you wanting to fling your monitor out the window when they get too complex).

Here's a couple handy custom expressions and examples on top of the ones that ship with the help. I keep up with the bad short-hand habbit of NOT declaring floats with float 'cause you don't have to but you do have to explicitly declare all other types such as int, vector, matrix, etc. These expression functions pre-date Python and some of the more recent expression functions in Houdini. A couple pre-date Houdini and are still useful today. Hopefully this gives you a good idea as to the syntax and how you can write your own custom expressions:

[CODE]
#
# These are custom expression functions created by Jeff Wagner for use
# in Action. These function can be used in any Action expression.
#

inv(n, d) # Return inverse allowing for 0
{ # n = numerator, d = denominator
if (d == 0) return 0;
return (n/d);
}
[/CODE]

[CODE]
waveroll(t, now)
{
return pow(sin(t*360 + now*360)*.5+.5, 1.5);
}[/CODE]

[CODE]
# used to create a water effect in a point SOP within houdini

noiseroll(x, z, xscale, zscale, wfreq, nfreq, namp, nvel, now)
{
return waveroll((x*xscale + z*zscale) +
snoise((x+nvel)*nfreq, nvel*now, z*nfreq)*namp, now);
}[/CODE]

[CODE]
wavenoise(x, y, z, amp, rough, exponent)
{
n = 0;
l = 1;
for (i = 0; i < 3; i++)
{
n += snoise(x, y, z) * l;
x *= 2;
y *= 2;
z *= 2;
l *= rough;
}
if (n < 0)
n = -pow(-n, exponent);
else n = pow( n, exponent);
return n * amp;
}
[/CODE]

[CODE]
float moveParticles(float value)
{
if (value > 0)
{
temp = value - 1;
return temp;
}
else
{
if (rand($F) < 0.5)
return 0;
else
return 150;
}
}[/CODE]

[CODE]
# Simple example of writing to and returning a vector type
vector
test1()
{
vector v = vector3(0,1,0);
return v;
}[/CODE]

[CODE]
string in_group()
{
string inputSop = strcat( "../", opinput(".",0) );
string inputGroups = primgrouplist( inputSop );
float nargs = argc( inputGroups );

for ( i = 1; i <= nargs; i++ )
{
string myGroup = arg( inputGroups, i-1 );
float inGroup = hasprim ( myGroup, inputSop, $PR );
if ( inGroup == 1 ) return i;
}
} [/CODE]

[CODE]
string k_getfiles(string dir,float rand_base)
{
string files = run("uls -p" + dir);
float nargs = argc(files);
float rand_file = round(fit(rand(rand_base),0,1,0,nargs-1));
string rand_name = arg(files,rand_file);
return dir+"/"+rand_name;
}[/CODE]

[CODE]


string strreplace(string srcstr; string replace; string with)
{
float i = -1;
string left = "";
string right = srcstr;

i = index(right, replace);
while (i >= 0) {

left = left + substr(right, 0, i) + with;
right = substr(right, i+strlen(replace), 999);

i = index(right, replace);
}

return left+right;
}


[/CODE]

  • Like 5
Link to comment
Share on other sites

Thanks Jeff, that's very a useful post.

Btw how does Houdini distinguish between multi line custom expressions vs 1 line hscript expressions? I assume because of the lack of {}s?

Also 1 liner hscript expressions are faster than multi line custom expressions?

Can you also please give me an example of a vector parameter used in POPs? I am not experienced in POPs but I didn't know there were single vector parameters in Houdini.

Also I wish we could access vector parameters using a single expression. I mean when you are doing something like this:

distance(ch("../fromx"), ch("../fromy"), ch("../fromz"), ch("../tox"), ch("../toy"), ch("../toz"))[/CODE]

I wish we could just do this:

[CODE]distance(ch("../from"), ch("../to"))[/CODE]

Basically have the ability to access vector parameters as a whole. I understand it wouldn't be applicable everywhere (i.e. directly using it inside another field except the POP parameters you mentioned) but in expressions and code, along with accompanying functions that support it i.e. distance ( vector3, vector3 ) would be amazing.

Is this an odd idea or have you guys thought about something like this before?

Thanks again Jeff.

Edited by magneto
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...