Declaring your own global variables in VEX

   45671   40   1
User Avatar
Member
543 posts
Joined: July 2005
Offline
Hi,

Is there a way to declare your own global variables in VEX, like one would do in C/C++ with a static modifier? I've got an Inline VOP that calls a function contained in an external file. This file has a number of functions which may or may not be called from the function referred to in the Inline VOP's “Inline VEX Code” field.

I thought something like this would work but was wrong:

#pragma hint avgValue hidden
#pragma hint avgAbsNs hidden

What am I missing?


Thanx,
Mark
========================================================
You are no age between space
User Avatar
Member
405 posts
Joined: July 2005
Offline
http://www.odforce.net/tips/shaderwriting1.php [odforce.net] Is a link to Odforce's Shading writing tutorial for Mantra. However its very basic. You are writing a Mantra Shader and not a Renderman or Mental Ray shader right? Aside from P, N and all those variables being global I don't know of how you can export other variables. Did you try the export command? Is this file a text file or a Database file? Could you show more of your code that involves you accessing your file. I am sorry if I am off I have alot of programming background and knowledge just not that strong in writing Mantra shaders.

Cheers,
Nate Nesler
User Avatar
Member
405 posts
Joined: July 2005
Offline
I have to ask why not just do an “include YourFile.h” or hpp just like you would an inline class definition.
User Avatar
Member
543 posts
Joined: July 2005
Offline
MatrixNAN
You are writing a Mantra Shader and not a Renderman or Mental Ray shader right? Aside from P, N and all those variables being global I don't know of how you can export other variables. Did you try the export command? Is this file a text file or a Database file?



Could you show more of your code that involves you accessing your file.

Hi Nate,

Yes, these are VEX/Mantra shaders. The problem is there's a lot going on in the code and it's best to break it up into seperate functions, but since there's way to create my own globals, I have to pass everything in and out of the functions via the function's arguments and it's return value. Sending a bunch-o-stuff into the function isn't a problem, but returning values can be limiting; actaully I “hijack” a vector variable and return 2 floats that aren't really vector components, but since the function can only return a single data item …

I'm using an Inline VOP that “includes” my external VEX My_Noise.h file, and then I call the function with something like:

$noise_output = My_Noise(P, size, noiseType, levels,
high, low, phase, filter);


Ther's so much we could do in VEX if there was other language features like arrays, structures, globals … it'd be prettty sweet. Can you imagine “Object Oriented” VEX? VEX Classes/Templates oh my!


–Mark
========================================================
You are no age between space
User Avatar
Member
543 posts
Joined: July 2005
Offline
MatrixNAN
I have to ask why not just do an “include YourFile.h” or hpp just like you would an inline class definition.

Oh it's being included, via the “Inline VOP”, but that's unrelated to declaring global vars in VEX.

Consider the following:


int MyFunc(int value_in)
{
int result;

result = MySub1(value_in);
result = MySub2(value_in, result);
return result;
}

int MySub1(int val) {
return val * val;
}

int MySub2(int val1, val2) {
return val1 * val2;
}


And call it from an Inline VOP by:

$my_result = MyFunc(some_value);

This is all good for one call to the function, but in the shading context, it gets called many times. If I desire to keep some value around to be used every time the shader calls this function, I'd need something “global and static” to ensure accessability and that it's contents can be relied upon between succesive calls to the function.



–Mark
========================================================
You are no age between space
User Avatar
Member
405 posts
Joined: July 2005
Offline
Well if you use Reference Variables you will not have to return anything. Just return a Void. The values get returned as pointer values directly into the memory allocated blocks for the varibles when they were created. Unless this is not allowed.

void MySub2(int val1 &, int val2 &, int solution &) {
solution = val1*val2;
}


That should work. Unless of course ref variables are not allowed. Yikes!!!

Cheers,
Nate Nesler 8)
User Avatar
Member
405 posts
Joined: July 2005
Offline
Ooops have not written a C++ program in 2 years got the order wrong on the & sigh figures. lol



void MySub2(int& val1, int& val2, int& solution) {
solution = val1*val2;
val1 = val1+val2;
val2 = val2+val1;
}


There we go. The values that get modified in the function would all be returned. I think you can only use C++ with this and not C. I can not remember if you can get away with this in the Object Oriented C in Linux. Yes C is dif between linux and windows. Interesting. Linux kernel is developed with an OOP C. I don't know what OS you are running but it will actually make a diff on this stuff. I have been on Linux for about 8 years now so I know some stuff. lol

Cheers,
Nate Nesler
User Avatar
Member
543 posts
Joined: July 2005
Offline
No, this is VEX code, not C/C++.

There's no passing by reference in VEX … at least not yet.


–Mark
========================================================
You are no age between space
User Avatar
Member
405 posts
Joined: July 2005
Offline
well that just takes all of the fun out of it. lol grrrr

:twisted: lol
User Avatar
Member
405 posts
Joined: July 2005
Offline
Ok but you do have strings, loops, and ifs so this should work.


// divide by powers of 10 to extract the numbers tested against char
// values in a loop. place the char values into a string denoted by
// spaces. Then return the string. extrapulate the values and assign
// them to the varibles in the right order.

string MySub2(int val1, int val2, int solution)
{
float result_num_r = 0;
int result_num_no_r = 0;
string value = “”;

solution = val1*val2;
val1 = val1+val2;
val2 = val2+val1;

for (count = 10; count < 1; count –)
{
result_num_r = solution /10*count;
result_num = result_num_r;
if (result_num >= 1)
{
if (result_num == 1)
value = value+“1”;
else if (result_num == 2)
value = value+“2”;
else if (result_num == 3)
value = value+“3”;
else if (result_num == 4)
value = value+“4”;
else if (result_num == 5)
value = value+“5”;
else if (result_num == 6)
value = value+“6”;
else if (result_num == 7)
value = value+“7”;
else if (result_num == 8)
value = value+“8”;
else if (result_num == 9)
value = value+“9”;
}
}

return value;
}

Yeah really ugly but hey it should work. Unless of course they happen to have a convert float to string or something like that. Guessing they don't so thats how you can get around that.

Cheers,
Nate Nesler

P.S. Hope you get a response from someone that knows how to export variables because this is ugly.
User Avatar
Staff
4517 posts
Joined: July 2005
Offline
xionmark
No, this is VEX code, not C/C++.

There's no passing by reference in VEX … at least not yet.

Actually, I'm pretty sure that _everything_ in VEX is passed by reference. So you can effectively return as many values as you want from your functions.

Mark
User Avatar
Member
543 posts
Joined: July 2005
Offline
mtucker
Actually, I'm pretty sure that _everything_ in VEX is passed by reference. So you can effectively return as many values as you want from your functions.

Mark

Huh? What?
Where's that documented?
And would one use the same form in the argument list as “passing by value”?

This warrants some investigation, possible can-o-worms …

Again, where is this documented? I've never heard this before.


–Mark
========================================================
You are no age between space
User Avatar
Member
941 posts
Joined: July 2005
Offline
Hi Mark,
xionmark
Again, where is this documented? I've never heard this before.
Yup. In file://$HHi/vex/html/compiler.html we get:

'Da Docs
Like with the RenderMan™ shading language, parameters to user functions are always passed by reference. This means that modifications in a user function affect the variable the function was called with.

So… careful what you modify in your user functions!! :shock:
Also; I've gotten into the habit of thinking about all global vars as reserved words (when working outside of the context functions, that is). That way you don't accidentaly clobber a global, causing a possibly hard-to-track bug.

Oh; and by-the-way…

PRMan doesn't pass parameters by reference (or rather; the compiler won't let you simply write to a parameter, even if the internal mechanics are “pass-by-reference”). If you want to overwrite a param in prman, you need to explicitly declare the parameter type as “output” – which, in the end, is no different than having to explicitly write the ‘&’ in C++. So; regardless of how it's managed internally, the end-effect for the programmer is that, in PRMan, parameters are not passed by reference.

Here's a “clobber-the-param” example in VEX:
float f(float x) { x-=.5; return x; }
surface testpbr() { float x=1; f(x); Cf=x;} // Cf is 0.5 !!!
A direct translation to SL simply doesn't compile:
float f(float x) { x-=.5; return x; }
surface testpbr() { float x=1; f(x); Ci=x;}

However; if you declare ‘x’ as output, then we have a “clobber-the-parm” function in SL:
float f(output float x) { x-=.5; return x; }
surface testpbr() { float x=1; f(x); Ci=x;}

The effect of having to write the “output” modifier is pretty significant – even if it's just to remind you that you're about to do something unusual.
I think I submitted this as an RFE a while back; but if I didn't, then I'd like to do so now
Mario Marengo
Senior Developer at Folks VFX [folksvfx.com] in Toronto, Canada.
User Avatar
Member
543 posts
Joined: July 2005
Offline
Hi Mario,

I remember reading that now! Arghhh …
However, I've been working mostly in VOPs lately and found something a little different …

Calling the same function from a Inline VOP:


$test_out1 = f(val);

float f(float x) {
x-=.5;
return x;
}


Will produce the error:

ERROR (1027) Illegal attempt to modify paramet
er “val”
x-=.5;

^


But not so in “regular” VEX, e.g. your example …

My brain hurts .. this shouldn't happen, right, calling a function from VOPs is the same as from VEX … it looks that way when I examine the code VOP's creates in /tmp/*.vfl

Also, the following code will produce the same error when compiled with vcc:


surface testpbr(float x = 0)
{
f(x);
Cf=x;
}


Forgot to mention, this is what I would expect from reading the docs, it says only user functions are passed by reference … so why is it different when called from VOPs?


–Mark
========================================================
You are no age between space
User Avatar
Member
941 posts
Joined: July 2005
Offline
xionmark
Calling the same function from a Inline VOP:

$test_out1 = f(val);

float f(float x) {
x-=.5;
return x;
}
That should be:

$test_out1 = f($val);

Otherwise it doesn't know that “val” is local to the encompasing scope (the context function created by all the VOPs in the network).

And I'm assuming the actual fdefinition of f() is coming from an include file (in the case of an inline vop) since you can't declare/define a function within a function.
I'm also assuming that “val” is simply the name you gave the input to the inline vop – something like the output of a constant vop, say. Notice that VEX *will* warn you if you tried to pass a global (say ‘s’) instead – this much is a good thing

Anyway; with that change, you'll get the same behaviour as my straight-vex example.

xionmark
My brain hurts .. this shouldn't happen, right, calling a function from VOPs is the same as from VEX … it looks that way when I examine the code VOP's creates in /tmp/*.vfl

It is. Except you gotta remember that the inline VOP is itself not a “function”, but a statement within a function. Which function? – the one defined by collecting all the VOPs in the network, which together (including your inline) create a single context function…. whew! 8)

xionmark
Forgot to mention, this is what I would expect from reading the docs, it says only user functions are passed by reference … so why is it different when called from VOPs?

Well… it's confusing, yes (and mostly because it's often hard to remember the context within which you're working when in VOPs)… but otherwise the behaviour is identical – i.e: the output of the assembled VOP network gets compiled by the same vcc as your hand-written code…


Time for another coffee
Mario Marengo
Senior Developer at Folks VFX [folksvfx.com] in Toronto, Canada.
User Avatar
Member
543 posts
Joined: July 2005
Offline
Hmm .. still getting an error …

This is the function declared in the include file:


float f(float x) {
x+=.1;
return x;
}


And it's being called from the Inline VOP:
$test_out1 = f($val);

val is from a Param VOP.

Either way, if val is preceded with a $ or not, I get the same error (after “re-sourcing” the include file in the Inline VOP; RFE: have a “reload include button” on the Inline VOP).

But of course if I declare a local var inside the function, it work's, i.e.:

float f(float x) {
float xx = x;
x+=.1;
return xx;
}


What's interesting too is that the generated VEX code (in /tmp) is the *same* whether I use the $ before the param or not!

Huh?

I've been confused by this $param thing; I read the docs, but I get values into the functions either way …

I can post a .hip if that would help.

It's so simple, I don't get it!

BTW: Houdini 6.0.383/Linux 7.3



–Mark
========================================================
You are no age between space
User Avatar
Member
543 posts
Joined: July 2005
Offline
Mario Marengo
Time for another coffee

Beat ya to it! Slluuuuurrrp …

Wanted to mention I have my code working, but I want to write it *correctly*, can't have any side effects (!) creeping out somewhere … :-)



–Mark
========================================================
You are no age between space
User Avatar
Member
941 posts
Joined: July 2005
Offline
hold on…

panic delivery!…..

l8r…
Mario Marengo
Senior Developer at Folks VFX [folksvfx.com] in Toronto, Canada.
User Avatar
Member
543 posts
Joined: July 2005
Offline
Mario Marengo
hold on…

panic delivery!…..

l8r…

Huh???

:?


OK, you're gonna love this. Houdini doesn't seem to like when there are more than one include file in a VOP network. It only generates one #include statement, see below. Yet, I have one function, f1(), in one include file, and the second function, f2(), in another file. Of course, when both functions are contained in a single file, all's good. Looks like a bug to me. Can't think of any reason why you'd be limited to including only a single file.


–Mark


This is the VOP gen'd code:
———————————-
#pragma opname test_vex
#pragma oplabel test_vex
#pragma opmininputs 0
#pragma opmaxinputs 0
#pragma label val1 Value1
#pragma label val2 Value2


#include <./houdini/vex/test_vex1.h>

surface
test_vex(float val1 = 0.1;
float val2 = 0.1)
{
int bound;
int bound1;
float test_out1;
float test_out2;
float sum;

// Code produced by: val1
bound = isbound(“val1”);

// Code produced by: inline1
test_out1 = f1(val1);

// Code produced by: val2
bound1 = isbound(“val2”);

// Code produced by: inline2
test_out2 = f2(val2);

// Code produced by: add1
sum = test_out1 + test_out2;

// Code produced by: output1
Af = sum;
}
========================================================
You are no age between space
User Avatar
Member
543 posts
Joined: July 2005
Offline
Also, the error message for the above problem with multiple include files is a bit misleading:


“/tmp/test_vex2331.vfl” line 40 ERROR (1041) A value type of “void” cannot be assigned
test_out2 = f2(val2);

^
“/tmp/test_vex2331.vfl” line 43 WARNING (2003) Write only or uninitialized variable “test_out2” used as argument 2 for “add”
sum = test_out1 + test_out2;

^

Wouldn't it be clearer if the first line mentioned that is was unaware of the symbol “f2”?



–Mark
========================================================
You are no age between space
  • Quick Links